shared_ptr 源码解析
_Ptr_base
源码
template <class _Ty>
class _Ptr_base { // base class for shared_ptr and weak_ptr
public:using element_type = remove_extent_t<_Ty>; //问题1 为什么使用remove_extent_t_NODISCARD long use_count() const noexcept {return _Rep ? _Rep->_Use_count() : 0;}template <class _Ty2>_NODISCARD bool owner_before(const _Ptr_base<_Ty2>& _Right) const noexcept { // compare addresses of manager objectsreturn _Rep < _Right._Rep;}_Ptr_base(const _Ptr_base&) = delete;_Ptr_base& operator=(const _Ptr_base&) = delete;protected:_NODISCARD element_type* get() const noexcept {return _Ptr;}constexpr _Ptr_base() noexcept = default;~_Ptr_base() = default;template <class _Ty2>void _Move_construct_from(_Ptr_base<_Ty2>&& _Right) noexcept {// implement shared_ptr's (converting) move ctor and weak_ptr's move ctor_Ptr = _Right._Ptr;_Rep = _Right._Rep;_Right._Ptr = nullptr;_Right._Rep = nullptr;}template <class _Ty2>void _Copy_construct_from(const shared_ptr<_Ty2>& _Other) noexcept {// implement shared_ptr's (converting) copy ctor_Other._Incref();_Ptr = _Other._Ptr;_Rep = _Other._Rep;}template <class _Ty2>void _Alias_construct_from(const shared_ptr<_Ty2>& _Other, element_type* _Px) noexcept {// implement shared_ptr's aliasing ctor_Other._Incref();_Ptr = _Px;_Rep = _Other._Rep;}template <class _Ty2>void _Alias_move_construct_from(shared_ptr<_Ty2>&& _Other, element_type* _Px) noexcept {// implement shared_ptr's aliasing move ctor_Ptr = _Px;_Rep = _Other._Rep;_Other._Ptr = nullptr;_Other._Rep = nullptr;}template <class _Ty0>friend class weak_ptr; // specifically, weak_ptr::lock()template <class _Ty2>bool _Construct_from_weak(const weak_ptr<_Ty2>& _Other) noexcept {// implement shared_ptr's ctor from weak_ptr, and weak_ptr::lock()if (_Other._Rep && _Other._Rep->_Incref_nz()) {_Ptr = _Other._Ptr;_Rep = _Other._Rep;return true;}return false;}void _Incref() const noexcept {if (_Rep) {_Rep->_Incref();}}void _Decref() noexcept { // decrement reference countif (_Rep) {_Rep->_Decref();}}void _Swap(_Ptr_base& _Right) noexcept { // swap pointers_STD swap(_Ptr, _Right._Ptr);_STD swap(_Rep, _Right._Rep);}template <class _Ty2>void _Weakly_construct_from(const _Ptr_base<_Ty2>& _Other) noexcept { // implement weak_ptr's ctorsif (_Other._Rep) {_Ptr = _Other._Ptr;_Rep = _Other._Rep;_Rep->_Incwref();} else {_STL_INTERNAL_CHECK(!_Ptr && !_Rep);}}template <class _Ty2>void _Weakly_convert_lvalue_avoiding_expired_conversions(const _Ptr_base<_Ty2>& _Other) noexcept {// implement weak_ptr's copy converting ctorif (_Other._Rep) {_Rep = _Other._Rep; // always share ownership_Rep->_Incwref();if (_Rep->_Incref_nz()) {_Ptr = _Other._Ptr; // keep resource alive during conversion, handling virtual inheritance_Rep->_Decref();} else {_STL_INTERNAL_CHECK(!_Ptr);}} else {_STL_INTERNAL_CHECK(!_Ptr && !_Rep);}}template <class _Ty2>void _Weakly_convert_rvalue_avoiding_expired_conversions(_Ptr_base<_Ty2>&& _Other) noexcept {// implement weak_ptr's move converting ctor_Rep = _Other._Rep; // always transfer ownership_Other._Rep = nullptr;if (_Rep && _Rep->_Incref_nz()) {_Ptr = _Other._Ptr; // keep resource alive during conversion, handling virtual inheritance_Rep->_Decref();} else {_STL_INTERNAL_CHECK(!_Ptr);}_Other._Ptr = nullptr;}void _Incwref() const noexcept {if (_Rep) {_Rep->_Incwref();}}void _Decwref() noexcept { // decrement weak reference countif (_Rep) {_Rep->_Decwref();}}private:element_type* _Ptr{nullptr};_Ref_count_base* _Rep{nullptr};template <class _Ty0>friend class _Ptr_base;friend shared_ptr<_Ty>;template <class _Ty0>friend struct atomic;friend _Exception_ptr_access;#if _HAS_STATIC_RTTItemplate <class _Dx, class _Ty0>friend _Dx* get_deleter(const shared_ptr<_Ty0>& _Sx) noexcept;
#endif // _HAS_STATIC_RTTI
};
remove_extent_t
原理和使用目的
template <class _Ty>
struct remove_extent { // remove array extentusing type = _Ty;
};template <class _Ty, size_t _Ix>
struct remove_extent<_Ty[_Ix]> {using type = _Ty;
};template <class _Ty>
struct remove_extent<_Ty[]> {using type = _Ty;
};template <class _Ty>
using remove_extent_t = typename remove_extent<_Ty>::type;
核心原因:统一处理数组和非数组类型
-
目的:创建统一的元素类型表示
-
效果:
-
对于非数组类型
T
→element_type = T
-
对于数组类型
T[N]
或T[]
→element_type = T
element_type* _Ptr{nullptr}; // 实际存储的指针 _Ref_count_base* _Rep{nullptr}; // 引用计数控制块
-
_Ptr
总是指向元素类型,而非整个数组类型
-
设计必要性分析
情况 1:数组类型处理
shared_ptr<int[]> arr(new int[5]); // _Ty = int[]
remove_extent_t<int[]>
→int
_Ptr
类型为int*
(指向第一个元素)- 而非
int(*)[]
(指向整个数组)
情况 2:非数组类型处理
shared_ptr<Widget> w(new Widget); // _Ty = Widget
remove_extent_t<Widget>
→Widget
_Ptr
类型为Widget*
为什么需要这种设计
指针运算一致性
// 对数组类型进行指针运算
shared_ptr<int[]> arr(new int[5]);
int* first = arr.get(); // int*
int* second = first + 1; // 合法指针运算// 如果 _Ptr 是 int(*)[] 类型:
int(*array_ptr)[] = arr.get();
// array_ptr + 1 将是未定义行为!
与标准库兼容
// 可与标准算法配合
shared_ptr<int[]> arr(new int[5]);
std::iota(arr.get(), arr.get() + 5, 0); // 需要元素指针类型
析构统一性
// 控制块中的删除器
template<typename T>
struct Ref_count {void destroy() {// 实际删除操作if constexpr (is_array_v<T>) {delete[] ptr; // 需要元素类型指针} else {delete ptr;}}T* ptr; // 这里 T 是原始类型
};
类型系统一致性
// 用户期望的 get() 行为
shared_ptr<Widget[5]> w(new Widget[5]);
Widget* p = w.get(); // 而非 Widget(*)[5]// 实现:
element_type* get() const noexcept {return _Ptr; // 总是返回元素指针
}
为什么要删除基类拷贝和赋值构造
防止浅拷贝导致资源管理灾难
智能指针的核心职责是管理资源生命周期。如果允许基类拷贝:
_Ptr_base p1(/* 管理某个资源 */);
_Ptr_base p2 = p1; // 如果允许拷贝
会导致:
- 两个对象共享同一个
_Rep
(引用计数控制块) - 析构时双重释放资源
- 引用计数管理混乱
强制子类实现正确的引用计数语义
不同子类需要不同的拷贝语义:
shared_ptr
拷贝:增加强引用计数weak_ptr
拷贝:增加弱引用计数- 基类无法统一处理这些语义
避免意外切片(Slicing)
考虑以下危险场景:
void process_base(_Ptr_base<int> base) {// 如果允许拷贝,这里会复制基类部分// 导致引用计数错误
}shared_ptr<int> sp = make_shared<int>(42);
process_base(sp); // 切片拷贝!
_Ref_count_base
源码
class __declspec(novtable) _Ref_count_base { // common code for reference counting
private:
#ifdef _M_CEE_PURE// permanent workaround to avoid mentioning _purecall in msvcurt.lib, ptrustu.lib, or other support libsvirtual void _Destroy() noexcept {_STD terminate();}virtual void _Delete_this() noexcept {_STD terminate();}
#else // ^^^ _M_CEE_PURE / !_M_CEE_PURE vvvvirtual void _Destroy() noexcept = 0; // destroy managed resourcevirtual void _Delete_this() noexcept = 0; // destroy self
#endif // _M_CEE_PURE_Atomic_counter_t _Uses = 1;_Atomic_counter_t _Weaks = 1;protected:constexpr _Ref_count_base() noexcept = default; // non-atomic initializationspublic:_Ref_count_base(const _Ref_count_base&) = delete;_Ref_count_base& operator=(const _Ref_count_base&) = delete;virtual ~_Ref_count_base() noexcept {} // TRANSITION, should be non-virtualbool _Incref_nz() noexcept { // increment use count if not zero, return true if successful// 原子地增加引用计数(仅当计数非零时)auto& _Volatile_uses = reinterpret_cast<volatile long&>(_Uses);// 读取当前值(平台相关方式)
#ifdef _M_CEE_PURElong _Count = *_Atomic_address_as<const long>(&_Volatile_uses);
#else//`__iso_volatile_load32` 是一个编译器内置函数,用于安全地从 volatile 位置读取 32 位值(即使 `long` 在 Windows 上是 32 位)。这确保读取操作不会被编译器优化掉,并且会按顺序执行。long _Count = __iso_volatile_load32(reinterpret_cast<volatile int*>(&_Volatile_uses));
#endif// CAS(Compare-And-Swap) 循环while (_Count != 0) {const long _Old_value = _INTRIN_RELAXED(_InterlockedCompareExchange)(&_Volatile_uses, _Count + 1, _Count);if (_Old_value == _Count) {return true;}_Count = _Old_value;}return false;}void _Incref() noexcept { // increment use count_MT_INCR(_Uses);}void _Incwref() noexcept { // increment weak reference count_MT_INCR(_Weaks);}void _Decref() noexcept { // decrement use countif (_MT_DECR(_Uses) == 0) {_Destroy();_Decwref();}}void _Decwref() noexcept { // decrement weak reference countif (_MT_DECR(_Weaks) == 0) {_Delete_this();}}long _Use_count() const noexcept {return static_cast<long>(_Uses);}virtual void* _Get_deleter(const type_info&) const noexcept {return nullptr;}
};
_Incref_nz介绍
代码解析见源码
核心技术
内存模型选择:宽松内存序 (Relaxed Memory Order)
_INTRIN_RELAXED(_InterlockedCompareExchange)
- 作用:使用
memory_order_relaxed
内存序 - 优势:
- 避免不必要的内存屏障
- 提升多核性能
- 适用场景:
- 引用计数操作是"独立"的
- 不需要保证操作顺序
- 只需保证原子性
CAS (Compare-And-Swap) 循环
sequenceDiagramparticipant Thread as 当前线程participant Memory as 共享内存loop CAS循环Thread->>Memory: 读取当前值_Countalt _Count == 0Thread-->>Thread: 返回falseelseThread->>Memory: 尝试原子交换alt 交换成功Thread-->>Thread: 返回trueelseThread->>Thread: 更新_Count=旧值endendend
3. 平台兼容性处理
#ifdef _M_CEE_PURE// .NET 托管环境处理long _Count = *_Atomic_address_as<const long>(&_Volatile_uses);
#else// 原生环境处理long _Count = __iso_volatile_load32(...);
#endif
__iso_volatile_load32
:- MSVC 内部函数
- 保证 volatile 读操作的原子性
- 避免编译器优化重排
_Atomic_address_as
:- 用于 .NET 互操作环境
- 桥接托管/非托管内存模型
4. Volatile 修饰符的双重作用
reinterpret_cast<volatile long&>(_Uses)
- 硬件层面:
- 防止编译器缓存寄存器
- 强制每次从内存读取
- 编译器层面:
- 禁止指令重排序优化
- 保证操作顺序性
设计必要性分析
解决弱引用提升的竞态条件
weak_ptr<T> wp = ...;
if (!wp.expired()) {// 此时可能已被其他线程释放shared_ptr<T> sp = wp.lock(); // 依赖_Incref_nz
}
确保对象存活性
性能优化考量
方法 | 平均周期 | 适用场景 |
---|---|---|
互斥锁 | 50-100ns | 复杂同步 |
CAS循环 | 10-20ns | 简单原子操作 |
无锁队列 | 20-40ns | 高竞争场景 |
_Ref_count
template <class _Ty>
class _Ref_count : public _Ref_count_base { // handle reference counting for pointer without deleter
public:explicit _Ref_count(_Ty* _Px) : _Ref_count_base(), _Ptr(_Px) {}private:virtual void _Destroy() noexcept override { // destroy managed resourcedelete _Ptr;}virtual void _Delete_this() noexcept override { // destroy selfdelete this;}_Ty* _Ptr;
};
构造函数
template <class _Ux,enable_if_t<conjunction_v<conditional_t<is_array_v<_Ty>,_Can_array_delete<_Ux>,_Can_scalar_delete<_Ux>>,_SP_convertible<_Ux, _Ty>>,int> = 0>explicit shared_ptr(_Ux* _Px) { // construct shared_ptr object that owns _Pxif constexpr (is_array_v<_Ty>) {_Setpd(_Px, default_delete<_Ux[]>{});} else {_Temporary_owner<_Ux> _Owner(_Px);_Set_ptr_rep_and_enable_shared(_Owner._Ptr, new _Ref_count<_Ux>(_Owner._Ptr));_Owner._Ptr = nullptr;}}
参数介绍
-
_Ux
:这是一个模板参数,表示传入的原始指针的类型。 -
enable_if_t<..., int> = 0
:这是一个SFINAE(Substitution Failure Is Not An Error)约束,确保只有满足特定条件的类型_Ux
才能使用这个构造函数。 -
约束条件由
conjunction_v
(逻辑与)组合两个条件:conditional_t<is_array_v<_Ty>, _Can_array_delete<_Ux>, _Can_scalar_delete<_Ux>>
:如果当前shared_ptr
管理的类型_Ty
是数组类型(is_array_v<_Ty>
为真),则检查_Ux
是否可以使用数组删除(即_Can_array_delete<_Ux>
)。否则,检查_Ux
是否可以使用标量删除(_Can_scalar_delete<_Ux>
)。这是为了确保删除器是匹配的(数组用delete[]
,非数组用delete
)。_SP_convertible<_Ux, _Ty>
:检查_Ux*
是否可以隐式转换为_Ty*
。这确保了传入的指针类型与shared_ptr
管理的类型兼容。
-
如果这两个条件都满足,
enable_if_t
会得到一个类型int
,并设置默认值为0,这样这个构造函数就可用。否则,这个构造函数会被从重载集中移除。
相关问题
构造函数为模版的原因
-
在 C++ 的
shared_ptr
实现中,即使类模板已经定义为shared_ptr<_Ty>
,其构造函数为什么仍然使用成员函数模板(而不是普通函数) -
核心原因:支持多态和灵活构造
-
多态指针支持
// 需要允许从派生类指针构造基类指针 class Base {}; class Derived : public Base {};shared_ptr<Base> p(new Derived); //
-
删除器类型擦除
需要支持任意类型的删除器: // 普通函数无法处理不同类型的删除器 void f() { auto deleter = [](FILE* p) { fclose(p); }shared_ptr<FILE> fp(fopen("a.txt", "r"), deleter); }
-
SFINAE(Substitution Failure Is Not An Error)技术的工作原理
-
SFINAE 机制解析
enable_if_t<Condition, int> = 0
-
enable_if_t
的本质template <bool _Test, class _Ty = void> struct enable_if {}; // no member "type" when !_Testtemplate <class _Ty> // 特化:当条件为 true 时, 定义 type 类型 struct enable_if<true, _Ty> { // type is _Ty for _Testusing type = _Ty; };template <bool _Test, class _Ty = void> using enable_if_t = typename enable_if<_Test, _Ty>::type;
-
条件满足时(true)
enable_if_t<true, int> → typename enable_if<true, int>::type → int
此时模板实例化为:
template <class _Ux, int = 0> explicit shared_ptr(_Ux* _Px);
-
条件不满足时(false):
enable_if_t<false, int> → typename enable_if<false, int>::type → (无定义!触发替换失败)
-
-
conjunction_v
工作原理
-
基础定义(空包情况)
template <class... _Traits> struct conjunction : true_type {}; // If _Traits is empty, true_type
-
递归处理(至少一个类型特征时)
template <class _First, class... _Rest> struct conjunction<_First, _Rest...> : _Conjunction<_First::value, _First, _Rest...>::type {// the first false trait in _Traits, or the last trait if none are false };
-
_Conjunction
实现template <class _First, class... _Rest> struct conjunction<_First, _Rest...> : _Conjunction<_First::value, _First, _Rest...>::type {// the first false trait in _Traits, or the last trait if none are false };template <class _True, class _Next, class... _Rest> struct _Conjunction<true, _True, _Next, _Rest...> { // the first trait is true, try the next oneusing type = typename _Conjunction<_Next::value, _Next, _Rest...>::type; };
-
所有特征为
true
:返回最后一个特征的type
(继承自true_type
)。 -
遇首个
false
特征:立即返回该特征(继承自false_type
),短路后续计算。 -
空包:直接返回
true_type
。
-
-
效果
template <class... _Traits> _INLINE_VAR constexpr bool conjunction_v = conjunction<_Traits...>::value;
- 返回条件选择后的trait的value
**conditional_t
介绍 **
template <bool _Test, class _Ty1, class _Ty2>
struct conditional { // Choose _Ty1 if _Test is true, and _Ty2 otherwiseusing type = _Ty1;
};template <class _Ty1, class _Ty2>
struct conditional<false, _Ty1, _Ty2> {using type = _Ty2;
};template <bool _Test, class _Ty1, class _Ty2>
using conditional_t = typename conditional<_Test, _Ty1, _Ty2>::type;
is_array_v<_Ty> 介绍
template <class>
_INLINE_VAR constexpr bool is_array_v = false; // determine whether type argument is an arraytemplate <class _Ty, size_t _Nx>
_INLINE_VAR constexpr bool is_array_v<_Ty[_Nx]> = true;template <class _Ty>
_INLINE_VAR constexpr bool is_array_v<_Ty[]> = true;
-
使用方式
int arr[5]; is_array_v<decltype(arr)>
内部函数介绍
_Temporary_owner
template <class _Ux>
struct _Temporary_owner {_Ux* _Ptr;explicit _Temporary_owner(_Ux* const _Ptr_) noexcept : _Ptr(_Ptr_) {}_Temporary_owner(const _Temporary_owner&) = delete;_Temporary_owner& operator=(const _Temporary_owner&) = delete;~_Temporary_owner() {delete _Ptr;}
};// _Temporary_owner 是一个在 C++ 标准库中使用的辅助类,用于确保在构造函数中分配的资源在异常发生时能够被正确释放。它的主要目的是在构造函数中创建一个临时的资源管理对象,以确保即使在构造函数抛出异常的情况下,资源也能被正确释放,从而避免资源泄露。
_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 _Pxthis->_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));}}}void _Set_ptr_rep_and_enable_shared(nullptr_t, _Ref_count_base* const _Rx) noexcept { // take ownership of nullptrthis->_Ptr = nullptr;this->_Rep = _Rx;}
这个模板 _Can_enable_shared
是 std::shared_ptr
实现中用于安全启用 std::enable_shared_from_this
功能的核心元编程组件.
核心目的是:
- 验证类
_Yty
是否正确继承了std::enable_shared_from_this
,并确保可以通过安全的指针转换访问基类。这是实现shared_from_this()
的关键前提。