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

发布于 2024-07-13 09:15:53 字数 468 浏览 4 评论 0原文

我有一个 Foo 对象和一个保存它实例的 std::list 。 我的问题是,当我将新实例添加到列表中时,它首先调用 ctor,然后也调用 dtor。 然后是另一个实例上的 dtor(根据 this 指针)。

单个实例被添加到列表中,但由于调用了它的 dtor(及其父级),因此该对象无法按预期使用。

这是一些简化的代码来说明问题:

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

此生挚爱伱 2024-07-20 09:15:53

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

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

也许您想存储指针而不是列表中的对象。 通过这样做,只复制指针而不是对象。 但是,通过这样做,您必须确保在完成后删除对象:

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

或者,您可以尝试使用某种“智能指针”类,例如来自 Boost 库的类。

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.

风筝有风,海豚有海 2024-07-20 09:15:53

您将在此处创建一个临时 Foo:

li.push_back( Foo() )

push_back 将该 Foo 复制到其内部数据结构中。 执行push_back后,临时Foo将被销毁,这将调用析构函数。

您将需要一个适当的复制构造函数,它可以增加您不想提前销毁的类成员的引用计数,或者将其设为私有以强制您采用指针解决方案。

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.

慕烟庭风 2024-07-20 09:15:53

使用这个对象来理解:

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";
    }
};

第一个 main

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

这里我们创建一个临时的 Foo 对象并调用push_back()。 临时对象被复制到列表中并且函数返回。 完成此语句后,临时对象将被销毁(通过析构函数)。 当列表被销毁时,它也会销毁它包含的所有对象(Foo 是一个带有析构函数的对象,因此销毁包括调用析构函数)。

所以您应该看到类似这样的内容:

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

在第二个示例中,您可以看到:

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

这里您在堆上动态创建一个对象。 然后调用push_back()。 这里指针被复制到列表中(指针没有构造函数/析构函数),因此不会发生其他情况。 该列表现在包含指向堆上对象的指针。 当函数返回时,什么也不做。 当列表被销毁时,它会销毁(注意销毁和删除之间的细微差别)它包含的对象(指针),但指针没有析构函数,因此不会发生任何泄漏内存的情况。

所以你应该看到这样的东西:

Constructed Object: 1

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
乖不如嘢 2024-07-20 09:15:53

这里实际发生的是,您将传递的对象的副本存储在列表中,因为您是按值而不是按引用发送它。 因此,第一个被调用的 dtor 实际上是在您传递给 Push_back 方法的对象上调用的,但此时已经创建了一个新实例,并且现在将其存储在列表中。

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

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.

紫﹏色ふ单纯 2024-07-20 09:15:53

使列表保存指针而不是实例可以解决调用析构函数的问题。 但我仍然想了解为什么会发生这种情况。

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

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());
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文