默认拷贝构造函数仅执行浅拷贝,对unique_ptr或裸指针成员会导致析构时double free;故需通过虚函数clone()实现深拷贝,由派生类各自定义复制逻辑。

为什么不能直接用默认拷贝构造函数
默认拷贝构造函数只做浅拷贝,如果类里有 std::unique_ptr、int* 或其他裸指针成员,拷贝后两个对象会指向同一块内存。析构时重复释放,触发 double free or corruption 错误。
典型场景:多态容器(比如 std::vector<:unique_ptr>></:unique_ptr>)需要复制其中的对象,但你只知道基类指针,不知道具体派生类型。
解决思路是让每个派生类自己负责“怎么复制自己”,基类提供统一接口——这就是 clone() 虚函数的由来。
如何定义和实现 virtual clone() 方法
基类声明纯虚函数 clone(),返回 std::unique_ptr<base>(推荐)或 Base*(需手动管理生命周期)。派生类重写它,内部 new 自己并返回。
立即学习“C++免费学习笔记(深入)”;
常见错误:返回栈对象地址、忘记 override、返回类型不协变(C++11 起支持协变返回类型,但必须是派生类指针/智能指针)。
-
Base类中声明:virtual std::unique_ptr<base> clone() const = 0; - 派生类
Derived中实现:std::unique_ptr<derived> clone() const override { return std::make_unique<derived>(*this); }</derived></derived> - 若用裸指针,返回
new Derived(*this),但调用方必须确保 delete,容易漏掉
clone() 和拷贝构造函数的关系
clone() 不替代拷贝构造函数,而是补充它:拷贝构造函数用于已知类型的栈/局部对象复制;clone() 用于运行时只知道基类指针的“类型擦除”场景。
性能上,clone() 必然涉及堆分配,比栈拷贝慢;兼容性上,所有派生类都必须实现它,否则无法实例化——这是设计契约,不是可选项。
注意:如果类里有非 trivial 成员(如含虚函数、自定义析构、移动操作),记得显式定义或 =default 拷贝构造/赋值,否则 *this 在 clone() 内部可能行为异常。
实际使用时最容易忽略的一点
很多人写了 clone(),却在容器里用错语义:比如把 std::vector<:unique_ptr>></:unique_ptr> 的元素直接 push_back 其 clone() 结果,却忘了 clone() 返回的是新对象,原对象还在——这没问题;但若误以为 clone() 会修改原对象,或期待它自动插入容器,就会逻辑错乱。
真正关键的细节是:clone 的结果必须被显式接管(赋值给智能指针变量、插入容器、传参等),没有隐式绑定,也没有 RAII 自动收尾——它只是个工厂函数,仅此而已。









