为什么我的析构函数被调用的次数比预期的要多
Why are my destructors being called a greater than number of times than expected?
我写这段代码是为了检查c++中析构函数的行为
#include <vector>
#include <iostream>
using namespace std;
class WrongDestructor
{
private:
int number;
public:
WrongDestructor(int number_) :
number(number_)
{}
~WrongDestructor() {
cout<<"Destructor of " <<number<<endl;
// throw int();
}
};
int main(int argc, char *argv[])
{
std::vector<WrongDestructor> wrongs;
for(int i = 0; i < 10; ++i) {
wrongs.push_back(WrongDestructor(i));
}
return 0;
}
我发现有趣的是我的程序的输出:
Destructor of 0
Destructor of 0
Destructor of 1
Destructor of 0
Destructor of 1
Destructor of 2
Destructor of 3
Destructor of 0
Destructor of 1
Destructor of 2
Destructor of 3
Destructor of 4
Destructor of 5
Destructor of 6
Destructor of 7
Destructor of 0
Destructor of 1
Destructor of 2
Destructor of 3
Destructor of 4
Destructor of 5
Destructor of 6
Destructor of 7
Destructor of 8
Destructor of 9
Destructor of 0
Destructor of 1
Destructor of 2
Destructor of 3
Destructor of 4
Destructor of 5
Destructor of 6
Destructor of 7
Destructor of 8
Destructor of 9
这意味着创建的对象比我想象的要多得多。当我在for循环中填充集合时,我预计集合中显然会有10个,接下来的10个可能会作为临时对象创建。但它们还有更多,其中一些甚至比其他的更经常被创造。
当vector
必须分配一个更大的内存块来容纳元素时,新元素会被移动到新的、更大的存储块中。因为您的类型没有定义移动构造函数或复制构造函数,所以您将获得编译器提供的默认复制构造函数。默认的复制构造函数对类中的所有成员执行简单的成员复制。
此外,使用push_back
插入元素本身需要将其移动或复制到vector
中。因此,假设编译器没有对此进行优化,您也会在那里获得副本。(请注意,您可以使用emplace_back
来避免这些副本。)
因此,您会提前将实例的多个副本插入到容器中,因为当例如1
被复制到vector
内部的较大内存缓冲区时,它会在旧的较小缓冲区中销毁。
通过定义复制和/或移动构造函数,您可以更清楚地看到这种行为:
#include <vector>
#include <iostream>
using namespace std;
class WrongDestructor
{
private:
int number;
public:
WrongDestructor(int number_) :
number(number_)
{}
// Copy constructor
WrongDestructor(WrongDestructor const& copied)
: number(copied.number)
{
cout << "Copied " << this->number << endl;
}
~WrongDestructor() {
cout<<"Destructor of " <<number<<endl;
// throw int();
}
};
int main(int argc, char *argv[])
{
std::vector<WrongDestructor> wrongs;
for(int i = 0; i < 10; ++i) {
wrongs.push_back(WrongDestructor(i));
}
return 0;
}
该程序提供以下输出:http://ideone.com/S5Zf41
您的向量没有预先确定的大小。当您将对象推回到向量上时,它必须重新分配向量本身以容纳新条目。这意味着将对象从内存缓冲区复制到新的缓冲区中。埃尔戈,当它这样做的时候,你会看到更多的副本。
您可以使用std::vector::reserve
为向量分配足够的空间。否则,向量需要为传入元素重新分配连续空间,这会导致大量副本。
std::vector<WrongDestructor> wrongs;
wrongs.reserve(10);
是的,看起来你在向量中添加了10个对象,但实际上又创建了10个,所以最后还会销毁10个对象。
你应该知道,当向量的内容越来越多时,向量会增加它容纳更多对象的容量,在这个过程中发生了什么?
如果vector没有空间容纳新对象,它将为更多对象创建一个更大的内存块,并复制它所拥有的对象。然后添加新的对象(通过push_back),它将销毁对象并释放满足它们的原始内存。
因此,当复制更多创建的对象时,当销毁原始对象时,将调用更多的析构函数。
最好的方法是提供复制构造函数,并在其中打印一些内容。并且在ctor中打印一些东西,你会看到整个过程。
你需要知道的更多的是向量的容量和储备。
- 为什么没有捕获我来自析构函数的异常
- 如何在关闭Qt控制台应用程序之前运行我的析构函数?
- 为什么我的析构函数中的异常没有触发 std::终止?
- 为什么我的析构函数被调用多次
- 为什么我的析构函数被调用的次数比预期的要多
- 我是否应该假设对象的析构函数在从 STL 容器中删除后立即调用?
- 我是否正确构建了这些引用和指针函数?如果是,我该如何显式调用我的析构函数
- 为什么我的析构函数导致我的链表出现问题
- 在这种情况下,我是否需要调用矢量的析构函数
- 我无法让我的析构函数在我的代码中工作
- 我的析构函数需要在这个函数中是什么
- boost::ptr_vector with arrays:我能确定它的析构函数调用delete[]而不是delete吗
- 为什么从 win32 计时器回调抛出时不调用我的析构函数?
- 为什么没有调用我的析构函数
- 为什么gcc链接器看不到我的析构函数
- 为什么我的析构函数被调用两次
- 为什么我的析构函数没有破坏我的对象,它仍然保留其成员变量值
- 我的析构函数每隔一秒调用一次
- 为什么我的析构函数被调用,我如何修复它
- 如何正确删除ptrs数组?我的析构函数似乎丢失了实际的对象