std::unique_ptr悬空指针问题修复及clone()用法合理性咨询
C++代码修复与克隆模式实践分析
问题代码与现象
以下是运行的C++代码:
#include <memory> #include <iostream> class A { public: virtual std::unique_ptr<A> clone() = 0; }; class B : public A { private: int b0; public: B(const B& b) { b0 = b.get_b0(); } B(const int& b0) : b0(b0) {} std:: unique_ptr<A> clone() { return std::make_unique<B>(*this); } const int& get_b0() const { return b0; } int& get_b0() { return b0; } }; class box { private: std::unique_ptr<A> o; public: box(const box& sp) { o = sp.o->clone(); } box(std::unique_ptr<A> o) : o(std::move(o)) {} std::unique_ptr<A> get_o() { return o->clone(); } }; void foo(std::unique_ptr<box> sp) { std::unique_ptr<A> o = sp->get_o(); if(const B *ptr1 = dynamic_cast<const B*>(o.get())) std::cout << ptr1->get_b0() << std::endl; if(const B *ptr = dynamic_cast<const B*>(sp->get_o().get())) std::cout << ptr->get_b0() << std::endl; } int main() { B b(100); box sp(std::make_unique<B>(b)); foo(std::make_unique<box>(sp)); return 0; }
运行输出:
100 3579964222 (some random integer!!!)
将std::unique_ptr替换为std::shared_ptr后代码可正常运行,但业务场景中shared_ptr可能引发问题(修改一个对象可能影响其他共享实例),现需修复代码并确认当前clone()用法是否为良好实践。
代码修复
错误原因
第二个if语句中,sp->get_o().get()返回的指针指向的是临时unique_ptr管理的对象:get_o()返回的unique_ptr是临时对象,在该行表达式执行完毕后就会被销毁,其管理的A对象也会被释放,导致ptr成为野指针,读取到随机内存值。而shared_ptr因为引用计数机制,临时对象销毁后只要还有其他引用就不会释放对象,所以不会出现问题,但这并非正确的解决方式。
修复方案
将临时的unique_ptr存储到变量中,确保对象生命周期覆盖指针的使用:
void foo(std::unique_ptr<box> sp) { std::unique_ptr<A> o = sp->get_o(); if(const B *ptr1 = dynamic_cast<const B*>(o.get())) std::cout << ptr1->get_b0() << std::endl; // 修复:先保存临时unique_ptr,避免对象提前销毁 std::unique_ptr<A> temp_o = sp->get_o(); if(const B *ptr = dynamic_cast<const B*>(temp_o.get())) std::cout << ptr->get_b0() << std::endl; }
clone()用法的合理性
当前的clone()设计属于原型模式的标准实现,是良好的代码实践:
- 使用
std::unique_ptr作为返回值,明确表达了克隆后对象的所有权完全转移给调用者,避免了共享所有权带来的意外修改问题,完全适配你的业务场景需求。 - 虚函数
clone()定义了基类的克隆接口,子类实现具体的克隆逻辑,符合面向对象的多态设计原则。 - 可以进一步优化:将
clone()声明为const成员函数,因为克隆操作不应该修改原对象,提升代码的const正确性:// 基类修改 virtual std::unique_ptr<A> clone() const = 0; // 子类修改 std::unique_ptr<A> clone() const override { return std::make_unique<B>(*this); }
内容的提问来源于stack exchange,提问作者Dani
相关产品推荐
相关产品推荐

