如何正确将std::unique_ptr<B>转换为std::unique_ptr<A>?
正确实现std::unique_ptr到std::unique_ptr的转换
问题背景
在C++中,裸指针B*可以隐式转换为A*,通过动态调度调用对应方法。但std::unique_ptr<B>无法直接隐式转换为std::unique_ptr<A>,手动提取裸指针封装成std::unique_ptr<A>会触发双删除问题:Printer函数返回时释放一次对象,main中bPtr销毁时再次释放同一对象。
原始问题代码:
#include <iostream> #include <memory> class A { public: virtual void Print() = 0; }; class B : public A { public: void Print() { std::cout<<"Hello, world\n"; } }; void Printer(std::unique_ptr<A> aPtr) { aPtr->Print(); } int main() { std::unique_ptr<B> bPtr = std::make_unique<B>(); Printer(std::unique_ptr<A>(bPtr.get())); // 导致双删除 }
解决方案
1. 使用std::move转移所有权
std::unique_ptr是独占式智能指针,通过std::move可以将std::unique_ptr<B>的所有权转移给std::unique_ptr<A>,此时原bPtr会变为空指针,不会再参与对象销毁,避免双删除。
修改后的main函数:
int main() { std::unique_ptr<B> bPtr = std::make_unique<B>(); Printer(std::move(bPtr)); // 所有权完全转移给Printer的参数,bPtr此后为空 }
2. 调整Printer函数参数(不转移所有权)
如果不需要转移对象所有权,仅临时调用方法,可修改Printer的参数类型:
方案2.1:接收std::unique_ptr<A>&引用
void Printer(std::unique_ptr<A>& aPtr) { aPtr->Print(); } int main() { std::unique_ptr<B> bPtr = std::make_unique<B>(); Printer(bPtr); // 传递引用,所有权仍保留在bPtr }
方案2.2:直接接收裸指针
这种方式更简洁,适合仅调用方法、不涉及所有权管理的场景:
void Printer(A* aPtr) { if (aPtr != nullptr) { aPtr->Print(); } } int main() { std::unique_ptr<B> bPtr = std::make_unique<B>(); Printer(bPtr.get()); // 传递裸指针,所有权归bPtr所有 }
关键注意事项
必须确保基类A的析构函数为虚函数,否则当std::unique_ptr<A>销毁对象时,只会调用A的析构函数,无法触发B的析构逻辑,导致内存泄漏。修改后的A类定义:
class A { public: virtual void Print() = 0; virtual ~A() = default; // 添加虚析构函数 };
内容的提问来源于stack exchange,提问作者Aayush Anand
相关产品推荐
相关产品推荐

