如何确保std::weak_ptr不由临时std::shared_ptr创建?编译时限制use_weak_ptr方法参数的方案问询
这个问题很实用——毕竟把临时std::shared_ptr转成weak_ptr后,临时对象会立刻销毁,对应的weak_ptr直接变成空悬状态,完全达不到预期用途。下面给你两种编译期就能阻止这种错误的方案,简单直接且高效:
方法1:删除右值引用版本的重载
最直观的方式是为use_weak_ptr提供两个重载:一个接受左值引用的std::shared_ptr<Foo>(正常使用),另一个接受右值引用的版本并显式删除它。编译器会在遇到临时对象(右值)时匹配到被删除的重载,直接抛出编译错误。
#include <memory> class Foo {}; // 允许传入左值std::shared_ptr<Foo> void use_weak_ptr(const std::shared_ptr<Foo>& sp) { std::weak_ptr<Foo> wp = sp; // 在这里执行你的业务逻辑 } // 明确禁止传入右值(临时对象) void use_weak_ptr(std::shared_ptr<Foo>&&) = delete;
验证调用场景
- ✅ 允许的调用(左值传入):
auto shared = std::make_shared<Foo>(); use_weak_ptr(shared); // 编译通过,匹配左值引用版本 - ❌ 禁止的调用(临时对象传入):
use_weak_ptr(std::make_shared<Foo>()); // 编译错误:尝试调用已删除的函数
方法2:用模板+类型约束实现更严格的检查
如果你想要更灵活的模板化方案,也可以借助std::is_lvalue_reference和SFINAE机制,强制要求参数必须是左值引用,同时约束类型为std::shared_ptr<Foo>:
#include <memory> #include <type_traits> class Foo {}; template <typename T, typename = std::enable_if_t<std::is_lvalue_reference_v<T>>> void use_weak_ptr(T&& sp) { // 额外的类型检查:确保传入的是std::shared_ptr<Foo> static_assert(std::is_same_v<std::decay_t<T>, std::shared_ptr<Foo>>, "use_weak_ptr only accepts lvalue std::shared_ptr<Foo>"); std::weak_ptr<Foo> wp = sp; // 业务逻辑 }
这种方案的好处是可以在编译期给出更明确的错误提示(通过static_assert),帮助开发者快速定位问题。
核心原理
两种方案都是利用C++的重载解析规则:临时对象属于右值,会优先匹配右值引用的函数;当我们删除该重载或通过模板约束排除右值时,编译器就会直接报错,从根源上阻止无效调用。
内容的提问来源于stack exchange,提问作者Croolman
相关产品推荐
相关产品推荐

