如何禁止派生类场景下临时shared_ptr向weak_ptr转换
适配继承场景的weak_ptr防临时构造方案
问题背景
此前针对具体类型的防临时shared_ptr构造weak_ptr的方案,在涉及类继承的场景下会失效。
当前场景定义:
- 存在继承关系的两个类
Foo和IFoo,其中class Foo: public IFoo - 存在业务函数
void use_weak_ptr(std::weak_ptr<IFoo>)
需要确保编译阶段满足以下规则: - 传入左值
shared_ptr时正常编译:
auto shared = std::make_shared<Foo>(); use_weak_ptr(shared);
- 传入临时(右值)
shared_ptr时编译失败:
use_weak_ptr(std::make_shared<Foo>());
实现方案
原有方案失效的核心原因是:之前仅删除了接受std::shared_ptr<IFoo>&&的重载,当传入派生类Foo的右值shared_ptr时,隐式转换优先级会让其绕过该删除重载,直接构造std::weak_ptr<IFoo>传入函数。
只需要补充一个模板化的右值删除重载,拦截所有类型的右值shared_ptr即可,完整代码如下:
#include <memory> class IFoo {}; class Foo : public IFoo {}; // 业务主函数,接受weak_ptr执行逻辑 void use_weak_ptr(std::weak_ptr<IFoo>) { // 业务逻辑实现 } // 拦截所有右值shared_ptr,禁止从临时shared_ptr构造weak_ptr传入 template<typename T> void use_weak_ptr(std::shared_ptr<T>&&) = delete; int main() { // 符合预期:正常编译 auto shared = std::make_shared<Foo>(); use_weak_ptr(shared); // 符合预期:编译报错,调用了已删除的重载 // use_weak_ptr(std::make_shared<Foo>()); return 0; }
原理说明
- 当传入左值
shared_ptr时(无论类型是std::shared_ptr<IFoo>还是任意派生类的std::shared_ptr<T>),右值引用重载无法绑定左值,不会参与重载匹配,参数会正常隐式转换为std::weak_ptr<IFoo>调用业务主函数,逻辑正常。 - 当传入右值
shared_ptr时(包括std::make_shared返回的临时对象),模板重载可以直接推导出参数类型,无需任何类型转换,匹配优先级高于需要用户自定义转换的shared_ptr转weak_ptr路径,会直接匹配到已删除的重载,触发编译错误。该逻辑对所有继承层级的派生类都生效,不存在漏拦截问题。
内容的提问来源于stack exchange,提问作者Croolman
相关产品推荐
相关产品推荐

