You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

std::shared_ptr触发bad weak_ptr的C++标准规则解析

为什么特定MSVC调试模式下shared_from_this()会抛出bad_weak_ptr?

示例代码

a.h

#pragma once
#include <memory>

struct AAA;
std::shared_ptr<AAA> createAAA();

a.cpp

#include "A.h"
struct AAA : public std::enable_shared_from_this<AAA>{};
void destory_AAA(AAA* v) {
    v->~AAA();
}
std::shared_ptr<AAA> createAAA() {
    auto ret = std::make_shared<AAA>();
    // 检查make_shared后shared_from_this是否可用
    auto shared_from_ths = ret->shared_from_this();  // #1 此处抛出bad_weak_ptr
    return shared_from_ths;
}

main.cpp

#include "A.h"
void destory_AAA(AAA* v);
std::shared_ptr<AAA> unused_func(AAA* ptr) {
    return std::shared_ptr<AAA>{ ptr, destory_AAA };  // #2
}
int main()
{
    createAAA();
}

问题根源:模板实例化的一致性要求([temp.res.general] p6)

你怀疑的[temp.res.general] p6条款是解释该问题的正确规则,该条款规定:

模板实体的有效性可在实例化前检查。若出现以下情况,程序格式错误,无需诊断:

  • [...]
  • 假设实例化中对某构造的解释,与该模板实体任何实际实例化中对应构造的解释不同。

具体分析

#1和#2都会触发std::shared_ptr内部的_Set_ptr_rep_and_enable_shared模板函数实例化:

template <class _Ux>
void _Set_ptr_rep_and_enable_shared(_Ux* const _Px, _Ref_count_base* const _Rx) noexcept { // take ownership of _Px
    this->_Ptr = _Px;
    this->_Rep = _Rx;
    if constexpr (conjunction_v<negation<is_array<_Ty>>, negation<is_volatile<_Ux>>, _Can_enable_shared<_Ux>>) {
        if (_Px && _Px->_Wptr.expired()) {
            _Px->_Wptr = shared_ptr<remove_cv_t<_Ux>>(*this, const_cast<remove_cv_t<_Ux>*>(_Px));
        }
    }
}

两个翻译单元中AAA的类型完整性导致了模板实例化的解释差异:

  • 在a.cpp中,AAA是完整类型,编译器能识别它继承了enable_shared_from_this,因此_Can_enable_shared<AAA>被解析为true,if constexpr分支会被保留,代码会尝试初始化AAA内部的weak_ptr。
  • 在main.cpp中,AAA是不完整类型,编译器无法确定它是否继承enable_shared_from_this,_Can_enable_shared<AAA>被解析为false,if constexpr分支会被丢弃。

根据[temp.res.general] p6,同一个模板实体(_Set_ptr_rep_and_enable_shared<AAA>)在不同翻译单元中的实例化解释不一致,程序属于格式错误无需诊断的情况,MSVC调试模式下抛出的bad_weak_ptr就是这种不一致导致的后果。

ODR规则是否相关?

ODR规则([basic.def.odr] p15)要求同一个实体在所有翻译单元中的定义必须一致,但这里的问题并非std::shared_ptr模板定义违反ODR,而是模板实例化时的上下文差异导致解释不一致,属于模板特有的规则问题,和ODR没有直接关系。

内容的提问来源于stack exchange,提问作者xmh0511

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 23:51:16