2

I would like to know why an element I push back into a vector gets its destructor called in this situation:

#include <iostream>
#include <vector>

class Foo
{
public:
    Foo(int a)
     : m_a(a)
    {
        std::cout << "Foo ctor() " << m_a << std::endl;
    }
    ~Foo()
    {
        std::cout << "Foo dtor() " << m_a << std::endl;
    }
private:
    int m_a;
};

class FooStorage
{
public:
    static void createFoo(int a)
    {
        m_foos.push_back(Foo(a));
    }

    static std::vector<Foo> m_foos;
};

std::vector<Foo> FooStorage::m_foos;

int main()
{
    std::cout << "Before: " << FooStorage::m_foos.size() << std::endl;
    FooStorage::createFoo(53);
    std::cout << "After: " << FooStorage::m_foos.size() << std::endl;

    return 0;
}

This prints out the following:

Before: 0
Foo ctor() 53
Foo dtor() 53
After: 1
Foo dtor() 53

I'd like to know:

  • What gets deleted? (inbetween the 'Before' and 'After' couts)
  • Why does it get deleted?
  • What ends up in the vector?
manabreak
  • 5,415
  • 7
  • 39
  • 96

2 Answers2

9

You're creating a temporary object here:

m_foos.push_back(Foo(a));
//               ^^^^^^

That object's destructor will be called when the full expression has ended, but it will have been copied (or moved) by push_back() into the vector.

To prevent the creation of a temporary you can construct in-place using emplace_back():

m_foos.emplace_back(a);
Barry
  • 286,269
  • 29
  • 621
  • 977
David G
  • 94,763
  • 41
  • 167
  • 253
  • This does not work on IDE, the IDEs ARE the problem. Try compiling from the terminal. – Marine Galantin Feb 13 '22 at 00:29
  • Nothing appears from the compiler or at running time, but the results are completely false and suffer from undefined behavior. Check the accepted answer from: https://stackoverflow.com/questions/4303513/push-back-vs-emplace-back I posted this comment because I spent a few hours debugging a bug coming from CLion and the code was running completly fine from the terminal. In such case, I did not need `emplace_back` `push_back` worked. – Marine Galantin Feb 13 '22 at 19:19
1
m_foos.push_back(Foo(a));

This would result in two constructor call ( but it entirely depends on the compiler it can optimize away).

Foo(a)

is a temporary which would be constructed ( one constructor call )and then copied to vector ( copy constructor called ). As usual temporaries are alive till the end of expression where they are used. So when push_back ends it would call destructor for this temporary ( that's why you are seeing a call to destructor).

ravi
  • 10,994
  • 1
  • 18
  • 36
  • 1
    The copy/move constructor can't be elided here. Which one is called, depends. In this case it is copy ctor, because there is user-declared destructor. – Anton Savin Nov 07 '14 at 13:33