简体   繁体   English

在将对象添加到std :: list时,析构函数调用了对象

[英]Destructor called on object when adding it to std::list

I have a Foo object, and a std::list holding instances of it. 我有一个Foo对象,一个std :: list包含它的实例。 My problem is that when I add a new instance to the list, it first calls the ctor but then also the dtor. 我的问题是,当我向列表中添加一个新实例时,它首先调用ctor,然后调用dtor。 And then the dtor on another instance (according to the this pointer). 然后dtor在另一个实例上(根据this指针)。

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. 单个实例被添加到列表中,但由于调用了dtor(及其父项),因此无法按预期使用该对象。

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());
}

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. 当你push_back()你的Foo对象时,该对象被复制到列表的内部数据结构,因此调用另一个实例的Dtor和Ctor。

All standard STL container types in C++ take their items by value, therefore copying them as needed. C ++中的所有标准STL容器类型都按值获取它们的项目,因此根据需要复制它们。 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. 或者,您可以尝试使用某种“智能指针”类,例如Boost库。

You are creating a temporary Foo here: 你在这里创建一个临时的Foo:

li.push_back( Foo() )

push_back copies that Foo into its internal data structures. push_back将Foo复制到其内部数据结构中。 The temporary Foo is destroyed after push_back has been executed, which will call the destructor. 执行push_back后,临时Foo将被销毁,这将调用析构函数。

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. 您需要一个适当的复制构造函数来增加您不希望尽早销毁的类成员的引用计数 - 或者将其设置为私有以强制自己使用指针解决方案。

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(). 这里我们创建一个临时的Foo对象并调用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). 当列表被销毁时,它也会销毁它包含的所有对象(Foo是一个带有析构函数的对象,所以破坏包括调用析构函数)。

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(). 然后调用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

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. 因此,调用的第一个dtor实际上是调用传递给push_back方法的对象,但是当时创建了一个新实例,它现在存储在列表中。

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. 如果您不想创建Foo对象的副本,请将指针存储到列表中的Foo对象而不是对象本身。 Of course when doing it you will have to properly release memory on destruction of the list. 当然,在执行此操作时,您必须在销毁列表时正确释放内存。

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());
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM