user389955
user389955

Reputation: 10467

how to hold user defined type in STL stack?

My question is: is the following code about STL stack correct?

in the code, complex is a user defined class with constructor and destructor defined. after place 1, complex constructor and destructor are called 5 times respectively, and after place 2, complex destructor are called 5 times again due to pop(). so in total destructor are called more than constructor. IMO it should not happen. Is my code correct? if not correct how to correct it? suppose I still use stack rather than stack

#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;  
}  

Upvotes: 1

Views: 772

Answers (3)

zmb
zmb

Reputation: 7877

To answer your original question, there is nothing wrong with your code. However, your understanding is a little off.

As others have noted, mystack2.push(c) will call the complex's copy constructor. So in total you have 5 calls to the constructor, 5 to the copy constructor, and 10 to the destructor.

This brings up a few important points. As you've noticed, the following code:

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

First creates a complex (c), then a copy is added to the stack, and the original complex is destroyed when c goes out of scope. In C++11, the extra copy is unnecessary, and you can do the following:

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

Which will let the stack do the construction of the object, eliminating the need for a copy.

Another point which I think led to your confusion that the constructor was called 10 times, is that you said complex only defines a constructor and a destructor. If you don't define a copy constructor (and don't mark it private or deleted), one will be created automatically by the compiler. There's actually a little more to it than it with C++11, and I direct you to this question for details - Conditions for automatic generation of default/copy/move ctor and copy/move assignment operator?. The important thing to note, though, is that in this case your call to push was definitely calling a compiler-generated copy constructor.

Upvotes: 1

Karoly Horvath
Karoly Horvath

Reputation: 96276

To simplify it, I won't mention that each of these happens 5 times:

  • complex c(i,i); - constructor called
  • mystack2.push(c); - constructor called
  • c falls out of scope - destructor called
  • mystack2.pop(); - destructor called

Note: To see what's going on add trace messages in the constructor and destructor. Don't forget the rule of three.

Upvotes: 1

Brent Bradburn
Brent Bradburn

Reputation: 54969

You are probably not taking into account the copy constructor which would be called at

mystack2.push(c);

For value-type classes like complex, a copy constructor will be created for you automatically if you don't define your own.

You can create a copy constructor with something like this:

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

Upvotes: 1

Related Questions