我很困惑为什么析构函数被调用了很多次。
#include <iostream>
#include <vector>
class Box
{
public:
int x;
Box(int x);
~Box();
};
Box::~Box()
{
std::cout << x << " Destroyed\n";
}
Box::Box(int x)
{
this->x = x;
std::cout << x << " Created\n";
}
int main()
{
std::vector<Box> boxList;
for (int i = 0; i < 3; i++)
{
Box b(i);
boxList.push_back(b);
}
return 0;
}
输出:
0 Created
0 Destroyed
1 Created
0 Destroyed
1 Destroyed
2 Created
0 Destroyed
1 Destroyed
2 Destroyed
主要退出后将打印出来。我在析构函数中保留了一个getchar()来停止程序执行。否则我们不会看到这些线被打印出来。
0 Destroyed
1 Destroyed
2 Destroyed
有人可以解释一下。
答案 0 :(得分:1)
其他答案正确地提到了隐式copy constructor的调用。要查看这些调用,只需使用显式复制构造函数替换隐式复制构造函数:
#include <iostream>
#include <vector>
class Box
{
public:
int x;
int copy_nr;
Box(int x);
Box(const Box& other); //copy constructor
~Box();
};
Box::~Box()
{
std::cout << x << " (copy " << copy_nr << ") Destroyed" << std::endl;
}
Box::Box(int x) : x(x), copy_nr(0)
{
std::cout << x << " (copy " << copy_nr << ") Created" << std::endl;
}
Box::Box(const Box& other) : x( other.x ), copy_nr( other.copy_nr + 1 )
{
std::cout << x << " (copy " << other.copy_nr <<") Copied"
" (creating copy " << copy_nr << ")" << std::endl;
}
int main()
{
std::vector<Box> boxList;
for (int i = 0; i < 3; i++)
{
Box b(i);
boxList.push_back(b);
}
return 0;
}
在我的机器上,这会产生:
0 (copy 0) Created
0 (copy 0) Copied (creating copy 1)
0 (copy 0) Destroyed
1 (copy 0) Created
1 (copy 0) Copied (creating copy 1)
0 (copy 1) Copied (creating copy 2)
0 (copy 1) Destroyed
1 (copy 0) Destroyed
2 (copy 0) Created
2 (copy 0) Copied (creating copy 1)
0 (copy 2) Copied (creating copy 3)
1 (copy 1) Copied (creating copy 2)
0 (copy 2) Destroyed
1 (copy 1) Destroyed
2 (copy 0) Destroyed
0 (copy 3) Destroyed
1 (copy 2) Destroyed
2 (copy 1) Destroyed
其他计算机上的结果可能不同,因为std::vector
的实现可以决定何时重新分配其内部数组。
答案 1 :(得分:0)
这有两个原因。
首先,push_back
有时会扩展向量的大小,重新分配空间,复制所有对象,并销毁旧对象。要摆脱这种重新分配的工件,可以在循环之前添加boxList.reserve(3)
,并获得更易理解的输出:
0 Created
0 Destroyed
1 Created
1 Destroyed
2 Created
2 Destroyed
0 Destroyed
1 Destroyed
2 Destroyed
其次,push_back
制作本地b
对象的副本,然后销毁此b
。这解释了为什么上面输出中的每个对象在创建后很快就会被销毁。
最后三个电话当然是在节目退出时。
答案 2 :(得分:0)
0创建
创建本地Box b(0),复制到vector
0被摧毁
并销毁
1创建
现在创建了本地Box b(1)
0被摧毁
我认为此时您的矢量已重新分配,需要将对象复制到新存储中。原始向量中索引为0的对象在进程中被销毁
1被摧毁
本地Box被销毁
2创建
现在是本地Box的时间,索引为2
0被摧毁 1被摧毁
再次向量被重新分配并需要销毁原始位置中的对象
2被摧毁
本地变量被破坏
答案 3 :(得分:0)
这种情况正在发生,因为vector
正在使用Box
的默认复制运算符来创建对象的第二个实例,绕过您定义的构造函数。实际上,您确实有两个Box
:b
和boxList[i]
的实例。
注意如果将赋值运算符明确定义为private:
,编译器会发生什么class Box
{
public:
int x;
Box(int x);
~Box();
private:
Box& operator=( const Box& second ) {};
};
std中的编译器错误泛滥是由于在内部使用operator =来创建b
对象的精确副本。
答案 4 :(得分:0)
您将获得一个自动生成的复制构造函数。 如果你替换
Box b(i);
boxList.push_back(b);
与
boxList.emplace_back(i);
你得到了建设。
如果你也使用reserve(3)
(在添加项目之前),向量不必移动(调用析构函数的另一个可能原因),那么析构函数应该被正确调用3次