简体   繁体   English

std :: map如何调用值析构函数?

[英]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. 如果添加复制构造函数定义,则会看到析构函数调用的数量与构造函数调用的数量相匹配。

Live demo 现场演示

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[]使用以下逻辑:

  1. If the object doesn't exist, create it and then set it equal to a default-constructed object. 如果该对象不存在,请创建它,然后将其设置为与默认构造的对象相等。

  2. 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.

相关问题 std:map析构函数是否调用了Key Destructors以及Value Destructors? - Does std:map Destructor call Key Destructors as well as Value Destructors? std::map::clear 和元素的析构函数 - std::map::clear and elements' destructors delete []是否会调用析构函数? - Does delete[] call destructors? std :: swap如何在构造函数,赋值运算符和析构函数方面起作用? - How does std::swap work in terms of constructors, assignment operators, and destructors? 为什么`std :: exit`不能按预期触发析构函数? - Why does `std::exit` not trigger destructors as expected? 明确调用子析构函数还会调用父析构函数吗 - Does Explicitly Calling Child Destructors also call Parent Destructors 如何指定析构函数调用的顺序? - How to specify order of destructors call? 如何将std :: map与没有默认构造函数的值一起使用? - How should std::map be used with a value that does not have a default constructor? 在共享指针的值中调用std :: swap会调用一堆构造函数和析构函数 - Calling std::swap in shared pointers' values call a bunch of constructors and destructors 的std :: unordered_map <std::String, myClass*> - std :: unordered_map :: erase()调用myClass&#39;DTor? - std::unordered_map<std::String, myClass*> - does std::unordered_map::erase() call myClass' DTor?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM