在类对象向量中调用的额外析构函数

时间:2013-05-23 08:35:30

标签: c++

TestDelete::TestDelete(int i) {
    this->i = i;
    std::cout <<"TestDelete constructor for "<<this->i<<"\n";
}

TestDelete::~TestDelete() {
    std::cout <<"TestDelete destructor for "<<this->i<<"\n";
}

int main () {
  std::vector<TestDelete> pt;
  pt.push_back(TestDelete(1));
  pt.push_back(TestDelete(2));

  return 0;
}

以上代码段输出如下

  

1的TestDelete构造函数

     

1的TestDelete析构函数

     

2的TestDelete构造函数

     

1的TestDelete析构函数;

     

2的TestDelete析构函数;

     

1的TestDelete析构函数;

     

2的TestDelete析构函数;

我理解push_back的实现基于copy-swap概念,因为它会调用temperory对象的构造函数和析构函数。但是如果你注意到对object1的析构函数进行了额外的调用。

有人能解释一下这里发生了什么吗?

3 个答案:

答案 0 :(得分:1)

您正在破坏Rule of 3并且您的某个对象正在被复制,并且您正在查看该副本的析构函数。

如果添加复制构造函数和带有日志记录的复制赋值运算符,您将看到可理解的行为。

编辑:由于人们对评论中的这个答案感到困惑 - 这只是为了表明没有任何事情错误,只是如果你添加CC / CAO记录你会看到所有对象都被正确创建/分配/销毁。程序正确性不需要CC / CAO。下面有一个更好的答案,为什么std :: vector可能按照你在下面看到的顺序创建/分配/销毁。对由此引起的任何混乱道歉。

答案 1 :(得分:1)

让我们看看您的实施可能在做什么:

std::vector<TestDelete> pt;

创建大小为0的向量。

pt.push_back(TestDelete(1));

重新分配大小为1的向量。通过复制构造(移动构造)临时添加新元素。

pt.push_back(TestDelete(2));

重新分配大小为2的向量。这意味着复制构造(或移动构造)先前创建的元素,并删除原始元素。通过复制构造(移动构造)临时添加新元素。

Here is a live example,也有改进功能,可防止矢量重新分配。请注意,临时工仍在被破坏,这让我感到惊讶;我猜编译器可以删除副本。

答案 2 :(得分:0)

这是因为std::vector的调整大小政策。然后它被填满,它会因某种因素而增长。这需要新的内存分配+旧的内存释放(,因此析构函数的调用)。

例如,如果您事先保留内存,则不会调整大小:

$ cat main.cpp

#include <iostream>
#include <vector>

class TestDelete {
public:
        TestDelete(int);
        ~TestDelete();

        int i;
};

TestDelete::TestDelete(int i) {
    this->i = i;
    std::cout <<"TestDelete constructor for "<<this->i<<"\n";
}

TestDelete::~TestDelete() {
    std::cout <<"TestDelete destructor for "<<this->i<<"\n";
}

int main () {
  std::vector<TestDelete> pt;

  pt.reserve(10); // reserve memory for 10 objects
  pt.push_back(TestDelete(1)); // so no resize would be needed
  pt.push_back(TestDelete(2));

  return 0;
}

$ ./a.out

TestDelete constructor for 1 // temporary object constructed
TestDelete destructor for 1  // temporary object destructed
TestDelete constructor for 2  // temporary object constructed
TestDelete destructor for 2  // temporary object destructed
TestDelete destructor for 1  // vector destructed
TestDelete destructor for 2 // vector destructed