为什么在向向量添加实例时会调用我的类的析构函数?

260*_*607 15 c++ stl vector

似乎每次我向向量m_test添加一个对象时,都会调用析构函数方法.我错过了什么吗?我怎样才能防止这种情况发生?

class TEST
{
public:
    TEST();
    ~TEST();
    int * x;
};

TEST::TEST()
{
}

TEST::~TEST()
{
... it is called every time I push_back something to the vector ...
    delete x;
}

    vector<TEST> m_test;
    for (unsigned int i=0; i<5; i++)
    {
        m_test.push_back(TEST());
    }
Run Code Online (Sandbox Code Playgroud)

Ant*_*lov 12

这里的问题是你违反了三条规则.你的类有一个析构函数,所以你也需要一个复制构造函数和赋值运算符.或者,您不能允许复制您的类(例如,通过制作T(T const&)T& operator=(T const&)私有,或通过派生boost::noncopyable),然后调整向量的大小而不是使用push_back.

在第一种情况下,您可以像往常一样push_back选择自己的课程.在第二个,语法将是类似的

std::vector<TEST> vec(5);
// vec now has five default-constructed elements of type TEST.
Run Code Online (Sandbox Code Playgroud)

不做这两件事都是一个坏主意,因为你很可能在某些时候遇到双重删除问题 - 即使你认为你永远不会复制或分配一个TEST地方x != nullptr,明确禁止它会更安全.

顺便说一句,如果你有需要删除的成员指针当对象超出范围时,可以考虑使用智能指针像scoped_ptr,unique_ptr以及shared_ptr(也许auto_ptr如果您无法使用升压或C++ 11).


ssu*_*ube 8

当你push_back临时摧毁,它就不会被调用.

要在您的示例中修复它:

TEST test;
for (int i = 0; i < 5; ++i)
{
    m_test.push_back(test);
}
Run Code Online (Sandbox Code Playgroud)

应该只调用一次.

你的代码TEST在循环中创建一个临时的,使用它push_back,然后当循环结束/重复并被销毁时,临时超出范围.这恰好发生了,因为临时TEST需求得到了清理.

如果你想避免这种情况,你需要做其他事情,但每次推送都要做一个临时对象.一个可能的解决方案是:

vector<TEST> m_test(5); // Note reserving space in the vector for 5 objects

std::fill(m_test.begin(), m_test.end(), TEST()); // Fill the vector with the default ctor
Run Code Online (Sandbox Code Playgroud)

根据STL的优化方式,这可能不需要进行多次复制.

如果在TEST类中实现复制构造函数,您也可以获得更好的处理,例如:

TEST::TEST(const TEST & other)
{
    x = new int(*other.x); // Not entirely safe, but the simplest copy ctor for this example.
}
Run Code Online (Sandbox Code Playgroud)

这是否合适,或者你如何处理它,取决于你的类及其需求,但是当你定义了自己的常规构造函数和析构函数时,通常应该有一个复制构造函数(否则编译器会生成一个,在这种情况下,它将导致复制和挂起指针x).