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

时间:2021-08-29 06:59:49

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).

我有一个Foo对象,还有一个std :: list来保存它的实例。我的问题是,当我向列表中添加一个新实例时,它首先调用ctor,然后调用dtor。然后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());
}

5 个解决方案

#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.

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

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.

C ++中的所有标准STL容器类型都按值获取它们的项目,因此根据需要复制它们。例如,每当向量需要增长时,矢量中的所有值都可能被复制。

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库。

#2


You are creating a temporary Foo here:

你在这里创建一个临时的Foo:

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.

push_back将Foo复制到其内部数据结构中。执行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.

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

#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).

这里我们创建一个临时的Foo对象并调用push_back()。临时对象被复制到列表中,函数返回。完成此语句后,临时对象将被销毁(通过析构函数)。当列表被销毁时,它也会销毁它包含的所有对象(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(). 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.

在这里,您可以在堆上动态创建对象。然后调用push_back()。这里指针被复制到列表中(指针没有构造函数/析构函数),所以没有其他事情发生。该列表现在包含指向堆上对象的指针。当函数返回时,不执行任何其他操作。当列表被销毁时,它会破坏(注意破坏和删除之间的细微差别)它包含的对象(指针),但是指针没有析构函数,所以没有任何事情你会泄漏内存。

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.

这里实际发生的是你在列表中存储传递对象的副本,因为你是按值而不是通过引用发送它。因此,调用的第一个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. Of course when doing it you will have to properly release memory on destruction of the list.

如果您不想创建Foo对象的副本,请将指针存储到列表中的Foo对象而不是对象本身。当然,在执行此操作时,您必须在销毁列表时正确释放内存。

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

#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.

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

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.

C ++中的所有标准STL容器类型都按值获取它们的项目,因此根据需要复制它们。例如,每当向量需要增长时,矢量中的所有值都可能被复制。

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库。

#2


You are creating a temporary Foo here:

你在这里创建一个临时的Foo:

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.

push_back将Foo复制到其内部数据结构中。执行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.

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

#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).

这里我们创建一个临时的Foo对象并调用push_back()。临时对象被复制到列表中,函数返回。完成此语句后,临时对象将被销毁(通过析构函数)。当列表被销毁时,它也会销毁它包含的所有对象(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(). 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.

在这里,您可以在堆上动态创建对象。然后调用push_back()。这里指针被复制到列表中(指针没有构造函数/析构函数),所以没有其他事情发生。该列表现在包含指向堆上对象的指针。当函数返回时,不执行任何其他操作。当列表被销毁时,它会破坏(注意破坏和删除之间的细微差别)它包含的对象(指针),但是指针没有析构函数,所以没有任何事情你会泄漏内存。

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.

这里实际发生的是你在列表中存储传递对象的副本,因为你是按值而不是通过引用发送它。因此,调用的第一个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. Of course when doing it you will have to properly release memory on destruction of the list.

如果您不想创建Foo对象的副本,请将指针存储到列表中的Foo对象而不是对象本身。当然,在执行此操作时,您必须在销毁列表时正确释放内存。

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