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

时间:2015-10-28 18:14:36

标签: c++ constructor destructor stdmap

我有这段代码:

#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 ++的标志。简单编译。

3 个答案:

答案 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_typepair<int const, test>)。这是对构造函数的初始调用。

然后,当insert将其插入到map的内部存储中时,对-std=c++11的调用必须至少复制一次映射类型。显然,libstdc ++实现会在某处产生额外的副本,最多可添加两个复制结构,因此会有两个匹配的析构函数调用。如果添加复制构造函数定义,您将看到析构函数调用的数量与构造函数调用的数量相匹配。

Live demo

另外,请注意,通过添加pair标志,可以避免使用中间副本。如上面的代码所示,在这种情况下,实现使用mapped_type的分段构造来直接构造key_type中的map(和CardLayout)。内部存储。

答案 1 :(得分:0)

显然,您的operator[]使用以下逻辑:

  1. 如果对象不存在,请创建它,然后将其设置为默认构造对象。

  2. 返回对象的引用。

  3. 这是非常奇怪的行为。不需要额外的构造和分配。新对象应该首先默认构造。

答案 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编译的

相关问题