第一次破坏从何而来?

时间:2012-03-21 02:40:32

标签: c++

我试图练习以下代码:

#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

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

3 个答案:

答案 0 :(得分:5)

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

如果在插入任何对象之前调用O.reserve(2),那么将为向量提供足够的空间来对两个对象进行调整。所以它不需要重新分配,你不应该在main结束之前看到任何破坏。从技术上讲,如果您的编译器糟透了并且制作了不必要的副本,那么可能会有更多的破坏。但是,从你到目前为止所显示的内容来看,似乎并没有这样做。

答案 1 :(得分:1)

使构造函数和析构函数打印对象的内存地址,以便您可以遵循它的生命周期:

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

答案 2 :(得分:1)

在我们给复制构造函数打印语句后,我们得到了这个:

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)
}