CppCoreGuidelines R.33为何建议传递unique_ptr引用实现指针重置?
核心语义区分
你混淆了三种完全不同的unique_ptr操作场景,对应完全不同的传参方式:
- 修改调用方持有的
unique_ptr本身的指向(也就是规则里说的reseat):用unique_ptr<T>& - 从调用方完全拿走
unique_ptr的所有权:用传值unique_ptr<T>,调用时需移动 - 仅读写
unique_ptr指向的底层对象,不碰指针本身和所有权:直接传T*或T&即可,不需要传递unique_ptr本身
为什么reseat需要传引用
reseat的核心需求是:修改调用方栈上的那个unique_ptr对象本身,改完之后所有权仍然归调用方所有,调用方后续可以正常使用修改后的unique_ptr。
如果用传值的方式,函数拿到的是原unique_ptr的移动副本,修改的只是函数内部的局部变量,不会影响调用方的原指针,完全达不到reseat的效果。
示例:reseat场景
// 需求:替换调用方传入的unique_ptr指向的对象,所有权仍归调用方 void reset_to_new_widget(std::unique_ptr<Widget>& ptr) { // 直接修改调用方的unique_ptr,让它指向新构造的Widget ptr = std::make_unique<Widget>(/* 新的构造参数 */); } // 调用方代码 int main() { auto my_widget = std::make_unique<Widget>(100); std::cout << my_widget->get_value() << std::endl; // 输出100 reset_to_new_widget(my_widget); std::cout << my_widget->get_value() << std::endl; // 输出新对象的值,所有权仍在main return 0; }
传值的适用场景
只有当函数要完全接管unique_ptr的所有权时,才需要用传值+移动的方式,这种场景下调用方的原unique_ptr在函数调用后会变为空,不能再使用:
// 需求:接管传入的unique_ptr所有权,存入全局存储 void store_widget(std::unique_ptr<Widget> ptr) { global_widget_pool.push_back(std::move(ptr)); } // 调用方代码 int main() { auto my_widget = std::make_unique<Widget>(100); store_widget(std::move(my_widget)); // 此时my_widget已经为空,不能再访问 return 0; }
修改底层对象的场景
如果仅需要修改unique_ptr指向的底层对象,不需要修改指针本身的指向,也不需要变动所有权,直接传递底层对象的引用或指针即可,不需要传递unique_ptr本身:
void modify_widget(Widget& w) { w.set_value(200); } // 调用 modify_widget(*my_widget);
内容的提问来源于stack exchange,提问作者evolved
相关产品推荐
相关产品推荐

