我试图练习以下代码:
#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
对第一个析构函数的来源感到困惑。
答案 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)
}