第一次破坏是从哪里来的

Where is the first destruction come from?

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

我试图练习以下代码:

#include <iostream>
#include <vector>
using namespace std;
class A
{
public:
   virtual void f(){cout<<"A"<<endl;}
   virtual ~A(){cout<<"destruct A"<<endl;}
};
int main()
{
   A o1,o2;
   vector <A > O;
   O.push_back(o1);
   cout<<"1"<<endl;
   O.push_back(o2);
cout<<"test"<<endl;
return 0;
}

结果是:

1
destruct A
test
destruct A
destruct A
destruct A
destruct A

对第一个析构函数的来源感到困惑。

您的向量在第二次调用push_back时重新分配了内存缓冲区。这需要将其中的对象复制到新的缓冲区,并销毁原始对象。

如果在插入任何对象之前调用O.reserve(2),这将为向量提供足够的空间来容纳这两个对象。所以它不需要重新分配,在main结束之前你不应该看到任何破坏。从技术上讲,如果你的编译器很糟糕,并制作了不必要的副本,那么可能会有更多的破坏。然而,从你目前所展示的情况来看,它似乎并没有做到这一点。

在我们将语句打印到复制构造函数之后,我们得到了以下内容:

constructor A(0x7fff6e21e800)
constructor A(0x7fff6e21e7f8)
copy A(0x10e700910: From 0x7fff6e21e800)
1
copy A(0x10e700920: From 0x10e700910)
copy A(0x10e700928: From 0x7fff6e21e7f8)
destruct A(0x10e700910)
test
destruct A(0x10e700920)
destruct A(0x10e700928)
destruct A(0x7fff6e21e7f8)
destruct A(0x7fff6e21e800)

现在我们来看一下代码:

int main()
{
   A o1,
     // constructor A(0x7fff6e21e800)
         o2;
     // constructor A(0x7fff6e21e7f8)
   vector <A > O;
   O.push_back(o1);
     // copy A(0x10e700910: From 0x7fff6e21e800)
   cout<<"1"<<endl;
     // 1
   O.push_back(o2);
    // copy A(0x10e700920: From 0x10e700910)    // O needs to expand.
                                                // So a new range is created and the old value
                                                // copied from the old range to the new range.
                                                // Now we push o2 into the vector
    // copy A(0x10e700928: From 0x7fff6e21e7f8)
                                                // Now the old range has to be destroyed.
    // destruct A(0x10e700910)

   cout<<"test"<<endl;
    // test

   return 0;
                 // Before we exit destroy the old vector (of two items)
    // destruct A(0x10e700920)
    // destruct A(0x10e700928)
                // Now destroy o2 then o1
    // destruct A(0x7fff6e21e7f8)
    // destruct A(0x7fff6e21e800)
}

让构造函数和析构函数打印对象的内存地址,这样你就可以遵循它的生存期:

virtual void f() { cout << "A: " << std::hex << this << endl; }
virtual ~A(){ cout << "destruct A: " << std::hex << this << endl; }