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

C++ 将对象添加到std::list时,析构函数调用了该对象,c++,constructor,stdlist,C++,Constructor,Stdlist,我有一个Foo对象和一个std::list,其中包含它的实例。我的问题是,当我向列表中添加一个新实例时,它首先调用ctor,然后调用dtor。然后是另一个实例上的dtor(根据this指针) 将单个实例添加到列表中,但由于调用了其dtor(以及其父实例),因此无法按预期使用该对象 下面是一些简化的代码来说明这个问题: #include <iostream> #include <list> class Foo { public: Foo() {

我有一个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());
}
#包括
#包括
福班
{
公众:
Foo()
{ 
int断点=0;
}
~Foo()
{ 
int断点=0;
}
};
int main()
{
std::列表li;
李。推回(Foo());
}
当您向后推()您的Foo对象时,该对象被复制到列表的内部数据结构中,因此调用另一个实例的Dtor和Ctor

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

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

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

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

使列表包含指针而不是实例可以解决调用析构函数的问题。但我还是想知道为什么会这样

#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());
}
#包括
#包括
福班
{
公众:
Foo()
{ 
int断点=0;
}
~Foo()
{ 
int断点=0;
}
};
int main()
{
std::列表li;
推回(新Foo());
}

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

li.push_back( Foo() )
push_将该Foo复制到其内部数据结构中。临时Foo在push_-back执行后被销毁,这将调用析构函数


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

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


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

使用此对象了解:

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";
    }
};
在第二个示例中,您有:

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

啊!!这就解释了很多,这就是为什么这些实例不能工作,因为它们没有定义正确的复制构造函数?看起来指针是我最好的选择。mizipzor:您应该在编写类时决定它是否应该有一个copyctor和operator=。如果不是,你应该为这些声明私有原型。如果您的代码试图使用copy-ctor或operator=,那么您将得到一个错误。这里值得一提的是Boost-Pointer容器库()。例如,boost::ptr_向量比“等效”std::vector更有效,并且提供了更好的接口,因为您从未删除对象,实际上从未调用析构函数,并且存在内存泄漏
Constructed Object: 1
Constructed Object: 101
DestroyedObject: 1
DestroyedObject: 101
std::list<Foo*> li;
li.push_back(new Foo(1));
Constructed Object: 1