#include <vector> #include <iostream> using namespace std; class Base { char _type; public: Base(char type): _type(type) {} ~Base() { cout << "Base destructor: " << _type << endl; } }; class uncopyable { protected: uncopyable() {} ~uncopyable() {} private: uncopyable( const uncopyable& ); const uncopyable& operator=( const uncopyable& ); }; class Child : public Base,private uncopyable { int j; public: Child(): Base('c') {} ~Child() { cout << "Child destructor" << endl; } }; int main() { vector<Base> v; Base b('b'); Child c; v.push_back(b); v.push_back(c); return 0; }
我系统的输出是:
Base destructor: b Child destructor Base destructor: c Base destructor: b Base destructor: b Base destructor: c
我的问题是:
>为什么Base(具有类型b)的析构函数被调用三次而不是两次(我们是否有两个以上的对象b副本)?
>当我们复制Child类型的对象时会发生什么,考虑到其父级之一的copy-constructor是私有的.是不确定的行为?
>每当我尝试复制Child类型的对象时,我都希望得到编译时错误.我认为子的默认拷贝构造函数会尝试调用Uncopyable类的私有拷贝构造函数并导致编译错误.为什么不给出编译错误?
代码以这种方式设计的原因是因为Child类很大.
解决方法
int main() { vector<Base> v; // 1 Base b('b'); // 2 Child c; // 3 v.push_back(b); // 4 v.push_back(c); // 5 return 0; } // 6
>第1行:矢量v构造
>第2行:构建Base b(调用Base的构造函数)
>第3行:构造子c(调用Child的构造函数和Base的构造函数)
>第4行:v是最大容量的当前值,需要调整大小.
内存由v分配给Base的1个元素.
Base b复制到v [0](调用Base的复制构造函数).
>第5行:v再次处于最大容量,需要调整大小.
内存由v分配给Base的2个元素.
旧的v [0]被复制到新的v [0]中(调用Base的复制构造函数).
删除旧的v [0](调用Base的析构函数(“Base destructor:b”)).
将子c复制到v [1](调用Base的复制构造函数).
>第6行:c,b和v超出范围.
删除子c(调用Child的析构函数(“Child析构函数”),然后删除Base的析构函数(“Base destructor:c”).
基数b被删除(调用Base的析构函数(“Base析构函数:b”)).
删除Base v [0],v [1](调用Base的析构函数两次(“Base析构函数:b”,“Base析构函数:c”)).
没有内存泄漏 – 对于上面序列中的每个构造函数,都会调用相应的析构函数.
此外,您似乎对复制构造函数非常困惑.子c被传递给push_back作为Base& – 然后按预期调用Base的复制构造函数.由于Base的隐式复制构造函数不是虚拟的或覆盖的,因此让Child从uncopyable派生不会改变它.
注意,矢量< Base>不能存储Child类型的对象;它只知道为Base分配足够的内存.将Child实例分配给Base时发生的事情称为切片,虽然通常是无意识和误解,但在您描述的场景中看起来可能实际上是您想要的.