如何在STL堆栈中保存用户定义的类型?

时间:2013-05-07 23:51:59

标签: c++ stl

我的问题是:关于STL堆栈的以下代码是否正确?

在代码中,complex是一个用户定义的类,定义了构造函数和析构函数。 在第1位之后,复杂的构造函数和析构函数分别被调用5次, 并且在第2位之后,由于pop(),复杂的析构函数再次被调用5次。 因此总的析构函数被称为多于构造函数。 IMO它不应该发生。 我的代码是否正确?如果不正确怎么纠正呢?假设我仍然使用堆栈而不是堆栈

#include <stack>  
#include "complex.h"  
using namespace std;   
void test_stack(){   
stack<complex> mystack2;      
cout << "Pushing complex..." << endl;  
 for (int i=0; i<5; ++i) {   
  complex c(i,i);     
  mystack2.push(c);   
 }  
 //place 1  
 cout << "Popping out complex..." << endl;   
 while (!mystack2.empty()) 
 {  
    cout << " " << mystack2.top();  
    mystack2.pop(); //void pop();  
 }  
 //place 2  
 cout << endl;  
}  

3 个答案:

答案 0 :(得分:1)

为了简化它,我不会提到每个都发生了5次:

  • complex c(i,i); - 名为
  • 的构造函数
  • mystack2.push(c); - 名为
  • 的构造函数
  • c超出范围 - 名为
  • 的析构函数
  • mystack2.pop(); - 名为
  • 的析构函数

注意:要查看正在进行的操作,请在构造函数和析构函数中添加跟踪消息。不要忘记三个规则。

答案 1 :(得分:1)

您可能没有考虑将在

调用的复制构造函数
mystack2.push(c);

对于像complex这样的值类型类,如果你没有定义自己的复制构造函数,将自动为你创建。

您可以使用以下内容创建复制构造函数:

complex( complex const & other )
 : real(other.real)
 , imag(other.imag)
{
   cout<<"complex::copy_constructor called"<<endl;
}

答案 2 :(得分:1)

要回答原始问题,您的代码没有任何问题。但是,你的理解有点不对。

正如其他人所说,mystack2.push(c)会调用complex的复制构造函数。所以总共有5次调用构造函数,5次调用复制构造函数,10次调用析构函数。

这提出了一些重点。正如您所注意到的,以下代码:

for (int i=0; i<5; ++i) {   
    complex c(i,i);     
    mystack2.push(c);   
}

首先创建一个complex(c),然后将一个副本添加到堆栈中,当c超出范围时,原始复合体将被销毁。在C ++ 11中,不需要额外的副本,您可以执行以下操作:

for (int i=0; i<5; ++i) {   
    mystack2.emplace(i, i); 
}  

这将使堆栈完成对象的构建,从而无需复制。

我认为另一点导致您对构造函数被调用10次的困惑,就是您说complex只定义了构造函数和析构函数。如果您没有定义复制构造函数(并且不将其标记为私有或已删除),编译器将自动创建一个复制构造函数。实际上它比C ++ 11更多,我将引导您到这个问题了解详细信息 - Conditions for automatic generation of default/copy/move ctor and copy/move assignment operator?。但是,需要注意的重要一点是,在这种情况下,对push的调用肯定是调用编译器生成的复制构造函数。