1

我的问题是:以下关于 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;  
}  
4

3 回答 3

1

为简化起见,我不会提到这些中的每一个都发生了 5 次:

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

注意:要查看发生了什么,请在构造函数和析构函数中添加跟踪消息。不要忘记三法则。

于 2013-05-08T00:04:40.693 回答
1

您可能没有考虑将在以下位置调用的复制构造函数

mystack2.push(c);

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

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

complex( complex const & other )
 : real(other.real)
 , imag(other.imag)
{
   cout<<"complex::copy_constructor called"<<endl;
}
于 2013-05-08T00:31:12.397 回答
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 多一点,我将您引导到这个问题以获取详细信息 -自动生成默认/复制/移动 ctor 和复制/移动赋值运算符的条件?. 但是,需要注意的重要一点是,在这种情况下,您的调用push肯定是调用编译器生成的复制构造函数。

于 2013-05-08T00:44:50.120 回答