我有这段代码:
#include <iostream>
#include <map>
using namespace std;
class test{
public:
test() {
cout << "calling test ctor " << endl;
}
~test() {
cout << "calling test dtor " << endl;
}
void callme(){
cout << "call me " << endl;
}
};
int main () {
map<int, test> mp;
mp[0].callme();
mp[0].callme();
return 0;
}
该程序的输出是:
calling test ctor
calling test dtor
calling test dtor
call me
call me
calling test dtor
我很困惑std :: map如何在这里处理test :: ctors和dtors。
在执行此代码之前,我的假设是mp [0] .callme()将创建一个新的test
对象并在其上调用callme()
,如果我们调用mp [0] .callme (),然后它应该调用test :: dtor(因为我们在这里替换键0
),然后测试:: ctor创建一个新的test
对象,以便它可以调用{{1那个。显然我的假设在这里是错误的,因为输出根本不匹配。
有人可以对此有所了解吗?
EDIT1 :
gcc --version = gcc(GCC)5.1.1 20150422(Red Hat 5.1.1-1)
编译命令:
callme()
所以,没有g ++的标志。简单编译。
答案 0 :(得分:1)
通过使用命令g++ maps.cpp
进行编译,您在C ++ 03模式下调用g ++,这意味着它无法使用移动语义。
可以找到map::operator[]
实施的相关行here
if (__i == end() || key_comp()(__k, (*__i).first))
#if __cplusplus >= 201103L
__i = _M_t._M_emplace_hint_unique(__i, std::piecewise_construct,
std::tuple<const key_type&>(__k),
std::tuple<>());
#else
__i = insert(__i, value_type(__k, mapped_type()));
#endif
因此,在C ++ 11之前,mapped_type
(示例中为test
)默认构造为在您的示例中创建value_type
(pair<int const, test>
)。这是对构造函数的初始调用。
然后,当insert
将其插入到map
的内部存储中时,对-std=c++11
的调用必须至少复制一次映射类型。显然,libstdc ++实现会在某处产生额外的副本,最多可添加两个复制结构,因此会有两个匹配的析构函数调用。如果添加复制构造函数定义,您将看到析构函数调用的数量与构造函数调用的数量相匹配。
另外,请注意,通过添加pair
标志,可以避免使用中间副本。如上面的代码所示,在这种情况下,实现使用mapped_type
的分段构造来直接构造key_type
中的map
(和CardLayout
)。内部存储。
答案 1 :(得分:0)
显然,您的operator[]
使用以下逻辑:
如果对象不存在,请创建它,然后将其设置为默认构造对象。
返回对象的引用。
这是非常奇怪的行为。不需要额外的构造和分配。新对象应该首先默认构造。
答案 2 :(得分:0)
为了完整性:
#include <iostream>
#include <map>
using namespace std;
class test{
public:
test() {
cout << "calling test ctor " << endl;
}
test(const test&) {
cout << "calling copy ctor " << endl;
}
// test(test&&) {
// cout << "calling move ctor " << endl;
// }
test& operator = (const test&) {
cout << "calling copy assignment " << endl;
return * this;
}
// test& operator = (test&&) {
// cout << "calling move assignment " << endl;
// return * this;
// }
~test() {
cout << "calling test dtor " << endl;
}
void callme(){
cout << "call me " << endl;
}
};
int main () {
map<int, test> mp;
mp[0].callme();
mp[0].callme();
return 0;
}
在没有C ++ 11的情况下编译:
calling test ctor
calling copy ctor
calling copy ctor
calling test dtor
calling test dtor
call me
call me
calling test dtor
使用C ++ 11删除和编译移动语义的注释:
calling test ctor
call me
call me
calling test dtor
两者都是用g ++ 4.8.4编译的