为什么我的课'当我向向量添加实例时,会调用s析构函数

Why does my class's destructor get called when I add instances to a vector?

本文关键字:实例 添加 析构函数 调用 向量 我的 为什么      更新时间:2023-10-16

似乎每次向向量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());
    }

这里的问题是你违反了三条规则。你的类有一个析构函数,所以你也需要一个复制构造函数和一个赋值运算符。或者,您不能允许复制您的类(例如,通过使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.

不做这两件事都是个坏主意,因为你很可能在某个时候遇到双重删除问题——即使你认为你永远不会在x != nullptr的位置复制或分配TEST,明确禁止它也要安全得多

顺便说一句,如果您有成员指针,当对象超出范围时应该删除,请考虑使用智能指针,如scoped_ptrunique_ptrshared_ptr(如果您无法使用Boost或C++11,则可能使用auto_ptr)。

当您push_back时,它不被调用,当临时文件被销毁时,它被调用

在您的示例中修复它:

TEST test;
for (int i = 0; i < 5; ++i)
{
    m_test.push_back(test);
}

应该只调用一次。

您的代码正在循环中创建一个临时的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

根据STL的优化方式,这可能不需要制作多个副本。

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

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

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

若要避免销毁临时以避免复制构造函数,请考虑使用vector::resize或vector::template_back。下面是一个使用emplace_back:的示例

vector<TEST> m_test;
m_test.reserve(5); 
for ( uint i=0; i<5; i++ ) 
{
    m_test.emplace_back();
}

矢量元素将在不需要复制的情况下就地构建。当vt被销毁时,每个向量元素都会自动销毁。

需要c++0x(将-std=c++0x与gnu一起使用)。CCD_ 20当然也是必需的。

如果没有使用默认构造函数(例如,如果TEST::x是引用而不是指针),只需在对emplace_back()的调用中添加自变量,如下所示:

class TEST
{
public:
    TEST( int & arg) : x(arg) {;} // no default constructor
    int & x; // reference instead of a pointer.
};
. . . 
int someInt;
vector<TEST> m_test;
m_test.reserve(5);
for ( uint i=0; i<5; i++ ) {
    m_test.emplace_back( someInt ); // TEST constructor args added here.
}

所示的CCD_ 23是可选的,但确保在开始构建向量元素之前有足够的空间可用。

vector.push_back()将给定对象复制到其存储区域中。您在push_back()调用中构建的临时对象在被复制后立即被销毁,这就是您所看到的。某些编译器可能能够优化此副本,但您的编译器显然不能。

m_test.push_back(TEST());中,TEST()将创建一个临时变量。向量将其复制到自己的内存后,临时变量将被销毁。

你可以这样做:

vector<TEST> m_test(5, TEST());

析构函数不仅仅是为临时变量调用的。

当向量的容量发生变化时,也会调用析构函数。

这种情况经常发生在非常小的向量上,而在大向量上则不太常见。

这导致:

新的内存分配(大小基于增长指标,而不仅仅是大小+1)
将旧元素复制到新分配中
破坏旧矢量中的元素
释放旧的矢量内存
将新项的构造复制到新向量的末尾。

请参阅此处的第三个答案:当我将_返回到向量时调用析构函数