Destructor called on object when adding it to std::list

自古美人都是妖i 提交于 2019-12-03 12:44:39

问题


I have a Foo object, and a std::list holding instances of it. My problem is that when I add a new instance to the list, it first calls the ctor but then also the dtor. And then the dtor on another instance (according to the this pointer).

A single instance is added to the list but since its dtor (along with its parents) is called, the object cant be used as expected.

Heres some simplified code to illustrate the problem:

#include <iostream>
#include <list>

class Foo
{
public:
    Foo()
    { 
        int breakpoint = 0;
    }
    ~Foo()
    { 
        int breakpoint = 0;
    }
};

int main()
{
    std::list<Foo> li;
    li.push_back(Foo());
}

回答1:


When you push_back() your Foo object, the object is copied to the list's internal data structures, therefore the Dtor and the Ctor of another instance are called.

All standard STL container types in C++ take their items by value, therefore copying them as needed. For example, whenever a vector needs to grow, it is possible that all values in the vector get copied.

Maybe you want to store pointers instead of objects in the list. By doing that, only the pointers get copied instead of the object. But, by doing so, you have to make sure to delete the objects once you are done:

for (std::list<Foo*>::iterator it = list.begin(); it != list.end(); ++it) {
    delete *it;
}
list.clear();

Alternatively, you can try to use some kind of 'smart pointer' class, for example from the Boost libraries.




回答2:


You are creating a temporary Foo here:

li.push_back( Foo() )

push_back copies that Foo into its internal data structures. The temporary Foo is destroyed after push_back has been executed, which will call the destructor.

You will need a proper copy constructor that increases some reference count on the class members that you do not want to destroy early -- or make it private to force yourself on the pointer solution.




回答3:


Use this object to understand:

class Foo
{
public:
    Foo(int x): m_x(x)
    { 
    std::cout << "Constructed Object: " << m_x << ")\n";
    }
    Foo(Foo const& c): m_x(c.m_x+100)
    {
    std::cout << "Copied Object: " << m_x << ")\n";
    }
    ~Foo()
    {  
    std::cout << "Destroyed Object: " << m_x << ")\n";
    }
};

The First main

std::list<Foo*> li;
li.push_back(Foo(1));

Here we create a temporary Foo object and call push_back(). The temporary object gets copied into the list and the function returns. On completion of this statement the temporary object is then destroyed (via the destructor). When the list is destroyed it will also destroy all the obejcts it contains (Foo is an object with a destructor so destruction includes calling the destructor).

So you should see somthing like this:

Constructed Object: 1
Constructed Object: 101
DestroyedObject: 1
DestroyedObject: 101

In the second example you have:

std::list<Foo*> li;
li.push_back(new Foo(1));

Here you dynamically create an object on the heap. Then call the push_back(). Here the pointer is copied into the list (the pointer has no constructor/destructor) so nothing else happens. The list now contains a pointer to the object on the heap. When the function returns nothing else is done. When the list is destroyed it destroys (note the subtle difference betweens destroy and delete) the object it contains (a pointer) but a pointer has no destructor so nothing happens any you will leak memory.

So you should see somthing like this:

Constructed Object: 1



回答4:


What actually happens here is that you store a copy of the passed object in the list, because you're sending it by value instead of by reference. So the first dtor that is called is actually called on the object you pass to the push_back method, but a new instance had been created by then and it is now stored in the list.

If you don't want a copy of the Foo object to be created, store pointers to Foo objects in the list instead of the objects themselves. Of course when doing it you will have to properly release memory on destruction of the list.




回答5:


Making the list holding pointers instead of instances solves the problem with the destructor being called. But I still want to understand why it happens.

#include <iostream>
#include <list>

class Foo
{
public:
    Foo()
    { 
        int breakpoint = 0;
    }
    ~Foo()
    { 
        int breakpoint = 0;
    }
};

int main()
{
    std::list<Foo*> li;
    li.push_back(new Foo());
}


来源:https://stackoverflow.com/questions/515071/destructor-called-on-object-when-adding-it-to-stdlist

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!