如何从unique_ptr的裸指针向要求unique_ptr的函数传参(不修改API)
问题描述
我在项目中拥有一个unique_ptr变量up,该变量以裸指针形式传入函数fun1。现在需要在fun1内部调用仅读取指针内容、不做修改的函数fun2,但fun2的参数为std::unique_ptr&。请问如何从裸指针向fun2传递unique_ptr?是否存在无需修改API定义的解决方案?
相关代码
#include <iomanip> #include <iostream> #include <memory> #include <string> #include <type_traits> #include <utility> class Res { std::string s; public: Res(std::string arg) : s{ std::move(arg) } { std::cout << "Res::Res(" << s << ");\n"; } ~Res() { std::cout << "Res::~Res();\n"; } private: friend std::ostream& operator<< (std::ostream& os, Res const& r) { return os << "Res { s = " << r.s << "; }"; } }; // ptr is used just to read the content of the ptr. // No writing is done. fun2 calls another api // lets say api_fun that requires unique_ptr void fun2(std::unique_ptr<Res>& uniq_ptr){ // api_fun(uniq_ptr); std::cout << uniq_ptr.get() << '\n'; } void fun1(Res* ptr){ //std::unique_ptr<Res> tt(ptr); //fun2(std::move(tt));// this deletes the mem twice. } int main() { std::unique_ptr<Res> up(new Res("Hello, world!")); fun1(up.get()); // up will be used here too }
解决方案
首先明确:std::unique_ptr的核心是独占所有权,直接用裸指针构造新的unique_ptr会触发双重释放(如你注释的代码),这是绝对禁止的。
如果不能修改fun2的API,有两种可行方案:
方案1:临时构造不接管所有权的unique_ptr
给临时unique_ptr绑定一个空删除器,让它不会释放内存,这样既能满足fun2的参数类型要求,又不会干扰原unique_ptr的所有权:
void fun1(Res* ptr){ // 自定义空删除器,什么都不执行 auto noop_deleter = [](Res*) {}; std::unique_ptr<Res, decltype(noop_deleter)> temp_ptr(ptr, noop_deleter); fun2(temp_ptr); }
临时对象temp_ptr在fun1结束时销毁,由于删除器是空操作,原up的内存不会被释放,后续依然可以正常使用。
方案2:修改fun1的参数类型(更推荐)
既然fun1需要调用依赖unique_ptr的fun2,直接让fun1接收std::unique_ptr<Res>&而非裸指针,从根源上避免所有权混淆:
void fun1(std::unique_ptr<Res>& up){ fun2(up); } // main函数中直接传递引用 int main() { std::unique_ptr<Res> up(new Res("Hello, world!")); fun1(up); // up依然可以正常使用 }
这种做法完全符合C++智能指针的设计意图,消除了裸指针带来的所有权模糊问题,代码更安全、易维护。
注意事项
绝对不要直接用裸指针构造普通unique_ptr,这会导致两个unique_ptr同时拥有同一块内存的所有权,最终触发双重释放的未定义行为,这是C++智能指针使用中的典型错误。
内容的提问来源于stack exchange,提问作者pokche
相关产品推荐
相关产品推荐

