[英]How does std::map call value destructors?
I have this code : 我有这个代码:
#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;
}
The output of this program is : 该程序的输出为:
calling test ctor
calling test dtor
calling test dtor
call me
call me
calling test dtor
I am little confused how std::map is handling test:: ctors and dtors here. 我有点困惑std :: map如何在这里处理test :: ctors和dtors。
Before executing this code, my assumption was that mp[0].callme() would create a new test
object and call callme()
on that, and if we call mp[0].callme() again, then it should call test:: dtor (since we are replacing the key 0
here) and then test:: ctor to create a new test
object so that it could call callme()
on that. 在执行此代码之前,我的假设是mp [0] .callme()将创建一个新的
test
对象并在其上调用callme()
,如果再次调用mp [0] .callme(),则它应调用test :: dtor(因为我们在这里替换了键0
),然后进行测试:: ctor来创建一个新的test
对象,以便可以在其上调用callme()
。 Obviously my assumption is wrong here because output doesn't match at all. 显然,我的假设在这里是错误的,因为输出根本不匹配。
Could anyone please throw some light on this ? 任何人都可以对此有所了解吗?
EDIT1 : 编辑1 :
gcc --version = gcc (GCC) 5.1.1 20150422 (Red Hat 5.1.1-1) gcc --version = gcc(GCC)5.1.1 20150422(Red Hat 5.1.1-1)
Command to compile: 编译命令:
g++ maps.cpp
So, no flags with g++. 因此,g ++没有标志。 Simple compile.
简单编译。
By compiling using the command g++ maps.cpp
, you're invoking g++ in C++03 mode, which means it isn't able to use move semantics. 通过使用命令
g++ maps.cpp
编译,您可以在C ++ 03模式下调用g ++,这意味着它无法使用移动语义。
The relevant lines of the map::operator[]
implementation can be found here map::operator[]
实现的相关行可以在这里找到
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
So prior to C++11, the mapped_type
( test
in your example) is default constructed to create a value_type
( pair<int const, test>
in your example). 因此,在C ++ 11之前,默认构造了
mapped_type
(在您的示例中为test
)来创建value_type
(在您的示例中为pair<int const, test>
)。 This is the initial call to the constructor. 这是对构造函数的初始调用。
The call to insert
then has to copy the mapped type at least once when it inserts it into the internal storage for the map
. 到呼叫
insert
于是具有当将其插入到用于内部存储到至少一次复制映射类型map
。 Evidently, the libstdc++ implementation results in an additional copy somewhere, adding up to two copy constructions, and hence two matching destructor calls. 显然,libstdc ++实现会在某个地方产生一个额外的副本,从而增加了两个副本构造,并因此产生了两个匹配的析构函数调用。 If you add a copy constructor definition you'll see the number of destructor calls match the number of constructor calls.
如果添加复制构造函数定义,则会看到析构函数调用的数量与构造函数调用的数量相匹配。
Also, notice that by adding the -std=c++11
flag, you avoid the intermediate copies. 另外,请注意,通过添加
-std=c++11
标志,可以避免中间副本。 As seen in the code above, the implementation uses piecewise construction of the pair
in that case to directly construct the mapped_type
(and key_type
) in the map
's internal storage. 如上面的代码所示,在这种情况下,该实现使用该
pair
分段构造直接在map
的内部存储中构造被mapped_type
(和key_type
)。
Apparently, your operator[]
uses the following logic: 显然,您的
operator[]
使用以下逻辑:
If the object doesn't exist, create it and then set it equal to a default-constructed object. 如果该对象不存在,请创建它,然后将其设置为与默认构造的对象相等。
Return a reference to the object. 返回对该对象的引用。
That is very strange behavior. 那是非常奇怪的行为。 The extra construction and assignment is not needed.
不需要额外的构造和分配。 The new object should just be default constructed in the first place.
首先应该默认构造新对象。
For completeness: 为了完整性:
#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;
}
Compiled without C++11 gives: 不使用C ++ 11进行编译可得到:
calling test ctor
calling copy ctor
calling copy ctor
calling test dtor
calling test dtor
call me
call me
calling test dtor
Having comments on move semantics removed and compiled with C++11: 使用C ++ 11删除并编译了有关移动语义的注释:
calling test ctor
call me
call me
calling test dtor
Both are compiled with g++ 4.8.4 两者都是用g ++ 4.8.4编译的
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.