为什么我的析构函数被多次调用?

时间:2019-02-09 16:08:48

标签: c++ memory-management heap-memory

我创建了一个类并创建了该类的向量。我在析构函数中放入了cerr消息,以查看其何时被调用。我发现同一个析构函数被调用不止一次。这让我感到困惑。

#include <iostream>
#include <vector>

using namespace std;

class temp {
private:
    int _size = 1000;
    int _myBall [1000];
    int _id;
public:
    temp(int id) : _id(id) {}
    ~temp() {
        cerr << "destructor called. ID: " << _id << endl;
    }
};

int main() 
{
    vector<temp> myvec;
    int total_count = 5;
    int count = total_count;
    for(int count = 0;count < total_count; count++) {
        cerr << "count: " << count << endl;
        myvec.push_back(temp(count));
    }

    myvec.clear();
    cerr << "Hello World" << endl;
    system("pause");
    return 0;
}

控制台输出:

count: 0
destructor called. ID: 0
count: 1
destructor called. ID: 0
destructor called. ID: 1
count: 2
destructor called. ID: 0
destructor called. ID: 1
destructor called. ID: 2
count: 3
destructor called. ID: 0
destructor called. ID: 1
destructor called. ID: 2
destructor called. ID: 3
count: 4
destructor called. ID: 0
destructor called. ID: 1
destructor called. ID: 2
destructor called. ID: 3
destructor called. ID: 4
destructor called. ID: 0
destructor called. ID: 1
destructor called. ID: 2
destructor called. ID: 3
destructor called. ID: 4

2 个答案:

答案 0 :(得分:2)

由于每次std::vector调整大小时都会进行复制,因此调用了析构函数。

std::vector一旦构造便重新分配了预定数量的内存(足以容纳一定数量的temp实例)-即capacity。每次调用push_back时,它都会评估是否仍有足够的内存来容纳新实例。一旦填满,它实际上将重新分配另一块内存(足以分配更多的temp实例),然后复制(或移动,如果可能)所有现有实例。这些是您看到记录的析构函数调用。

如果您事先知道该向量需要保留多少个实例,则可以reserve达到该数量。

答案 1 :(得分:1)

让我们看看

myvec.push_back(temp(count));

在这里,您使用temp创建一个临时temp(count)对象。然后将其存储为向量中的 copy 。然后临时对象被破坏。

破坏临时对象是调用析构函数的一种情况。

然后,当向量动态调整自身大小时,它将内容复制到新的更大的数据存储器中。然后,较小数据存储器中的对象将被销毁。当然哪个导致析构函数被调用。调整大小和复制可能会发生多次。

关于向量的大小调整算法的工作方式,它是特定于实现的,但是一种常见的方法是在大小较小的情况下为每个push_back调整大小,然后随着大小的增加保留越来越大的块。

如果您不希望这种大小调整和复制,则只要知道要存储在向量中的元素数量,就可以设置特定的大小以开始,并使用常规的数组索引语法将其分配给元素,也可以reserve预先放置空格。