Why are C++ objects destroyed when initialized inside function? What can I do to prevent it?

Viewed 314

Here, when I push to the stack, why are the objects being destroyed?

#include <iostream>
#include <stack>

class One
{
private:
        int i;
public:
        One(int i) {this->i = i;}
        ~One() {std::cout << "value " << this->i << " is destroyed\n";}
};

int main()
{
        std::stack<One> stack;
        stack.push(One(1));
        stack.push(One(2));

        std::cout << "Now I'll stop\n";
}

I expected to see no output before Now I'll stop. But I get this

value 1 is destroyed
value 2 is destroyed
Now I'll stop
value 1 is destroyed
value 2 is destroyed

What should I do if I want prevent them from destroying?

3 Answers

One(1) and One(2) construct two temporary objects, which are passed to push and then copied (moved) into stack. Temporaries are destroyed after the full expression immediately.

If you want to avoid constructing temporaries you can use emplace instead.

Pushes a new element on top of the stack. The element is constructed in-place, i.e. no copy or move operations are performed.

E.g.

stack.emplace(1);
stack.emplace(2);

Let me add an illustrating detail to songyuanyao's answer which solves the actual problem.

If you add a copy constructor to class One, you will understand more easily what's going on and also how the balance between creation and destruction is maintained. (Didn't getting 4 destructions for two creations look like magic to you?)

As long as you don't define (or mention) a copy constructor, the compiler creates one for you that has a trivial implementation which does a bitwise copy of all members. So in your case, the behavior you observe may be confusing but doesn't do anything particularly bad. This of course will change as soon as you add members that involve more than just copying, for instance pointers to members that have to be destroyed somewhere...

In the following example, I added output to both constructors and also switched from assigning members in constructor body to initialiser list:

class One
{
  public:
    One(int rhs): i(rhs) {
        std::cout<< "value " << i << " was created from int\n";
    }
    One(const One& rhs): i(rhs.i) {
        std::cout<< "value " << i << " was created by copy\n";
    }
    ~One() {
        std::cout << "value " << i << " is destroyed\n";
    }

  private:
    int i;
};

When you do this stack.push(One(1)); it creates a temporary object called rvalue of One(1) which is then copied to Stack. So After Copy, temporary objects are getting destroyed.

Related