奇怪的物体破坏

Strange Destruction of objects

本文关键字:      更新时间:2023-10-16

我不明白为什么析构函数被调用了这么多次。

#include <iostream>
#include <vector>
class Box
{
    public:
        int x;
        Box(int x);
        ~Box();
};
Box::~Box()
{
    std::cout << x << " Destroyedn";
}
Box::Box(int x)
{
    this->x = x;
    std::cout << x << " Createdn";
}
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

main退出后,将打印此内容。我在析构函数中保留了一个getchar()来停止程序的执行。否则我们将看不到这些行被打印。

0 Destroyed
1 Destroyed
2 Destroyed

谁能解释一下。

其他答案正确地提到了隐式复制构造函数的调用。要查看这些调用,只需将隐式复制构造函数替换为显式复制构造函数:

#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的实现可以决定何时重新分配其内部数组。

有两个原因。

首先,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。这解释了为什么上面输出的每个对象在创建后很快就被销毁。

最后三个调用当然是在程序出口。

创建

0

创建本地Box b(0),复制到vector

0摧毁

,摧毁了

1创建

现在创建了本地Box b(1)

0摧毁

我认为此时你的向量被重新分配,需要将对象复制到新的存储空间。在原始向量中索引为0的对象在

过程中被销毁

1了

本地Box被销毁

2创建

现在是索引为2的本地Box的时间了

0摧毁1摧毁了

vector再次被重新分配需要销毁原位置的对象

2了

局部变量被销毁

发生这种情况是因为vector使用Box的默认复制操作符来创建对象的第二个实例,绕过了您定义的构造函数。实际上,您确实有两个Box实例:bboxList[i]

请注意,如果显式地将赋值操作符定义为private,会对编译器产生什么影响:

class Box
{
    public:
        int x;
        Box(int x);
        ~Box();
    private:
        Box& operator=( const Box& second ) {};
};

std中的大量编译错误是由于它在内部使用operator=来创建b对象的精确副本。

您将得到一个自动生成的复制构造函数。如果你替换

Box b(i);
boxList.push_back(b);

boxList.emplace_back(i);

你得到了现场施工。如果您还使用reserve(3)(在添加项之前),向量不必移动东西(调用析构函数的另一个可能原因),那么析构函数应该被调用3次

相关文章:
  • 没有找到相关文章