- 参考libc++ 7.0.1实现
- 简单实现源码:github.com/moyin1004/l...
shared_ptr数据定义
shared_ptr使用引用计数管理一个对象资源,简单定义如下:
cpp
template <typename T>
class SharedPtr {
private:
T* _ptr;
atomic<int>* _cntrl;
}
- 以上实现简化了标准库控制块,只有计数,缺少了弱引用计数(weak_ptr使用)
- 实际使用中,引用计数为0时,并没有释放控制块资源,但是资源已经不可用了,当弱引用计数计数也为0时,才会释放控制块资源
标准库控制块实现:
cpp
class __shared_count {
protected:
long __shared_owners_; // 用于shared_ptr 引用计数
};
class __shared_weak_count : private __shared_count {
long __shared_weak_owners_; // 用于weak_ptr 弱引用计数
};
class shared_ptr {
private:
element_type* __ptr_;
__shared_weak_count* __cntrl_;
};
源码中有一个值得学习的实现:
- 源码中拷贝赋值运算符函数使用了一个栈变量
- 相当于使用了构造函数增加要复制的资源的引用计数 和 析构函数减少现在管理的资源的引用计数
- 不用额外定义一个引用计数加减的函数,简化实现如下:
cpp
SharedPtr& operator=(const SharedPtr& sp) noexcept {
// 建立一个栈变量 相当于使用了构造函数和析构函数 不用额外定义一个引用计数加减的函数
SharedPtr(sp).swap(*this);
return *this;
}
void swap(SharedPtr& sp) {
std::swap(_ptr, sp._ptr);
std::swap(_cntrl, sp._cntrl);
}
weak_ptr
- weak_ptr数据成员和shared_ptr一致,多了几个成员函数,判断资源是否可用以及获得shared_ptr
- 未实现弱引用计数
cpp
template <typename T>
class WeakPtr {
public:
WeakPtr() {}
template <typename U>
WeakPtr(const SharedPtr<U>& sp) noexcept : _ptr(sp._ptr), _cntrl(sp._cntrl) {}
template <typename U>
WeakPtr& operator=(const SharedPtr<U>& sp) noexcept {
WeakPtr(sp).swap(*this);
return *this;
}
~WeakPtr() {
_ptr = nullptr;
_cntrl = nullptr;
};
SharedPtr<T> Lock() const noexcept {
SharedPtr<T> p;
if (_cntrl) {
int cur = _cntrl->load();
while (cur != 0) {
if (_cntrl->compare_exchange_strong(cur, cur + 1)) {
p._cntrl = _cntrl;
break;
}
}
}
if (p._cntrl) {
p._ptr = _ptr;
}
return p;
}
bool Expired() const { return _cntrl == nullptr || _cntrl->load() == 0; }
private:
void swap(WeakPtr& sp) {
std::swap(_ptr, sp._ptr);
std::swap(_cntrl, sp._cntrl);
}
T* _ptr;
atomic<int>* _cntrl;
};
源码中有一个值得学习的原子变量的使用方式:
- 当引用计数为0时,不可以操作,所以需要查询和修改两个操作
- 使用while循环compare_exchange_strong函数,只有当原子变量在查询后未变化时,才修改原子变量的值
enable_shared_from_this机制
enable_shared_from_this为了解决this指针转为shared_ptr的问题,例子如下:
cpp
std::vector<std::shared_ptr<Widget>> processedWidgets;
class Widget : public std::enable_shared_from_this<Widget> {
public:
void process() {
// 每次调用都会创建一个引用计数 会造成资源多次delete
// processedWidgets.emplace_back(shared_ptr<Widget>(this));
processedWidgets.emplace_back(shared_from_this());
}
};
shared_from_this函数会返回指向同一个控制款的shared_ptr,避免了资源多次delete
enable_shared_from_this内部使用weak_ptr实现,简化标准库后的实现源码如下:
cpp
template <typename T>
class EnableSharedFromThis {
public:
SharedPtr<T> SharedFromThis() { return SharedPtr<T>(_weak_this); }
SharedPtr<const T> SharedFromThis() const {
// const变量调用此函数
return SharedPtr<const T>(_weak_this);
}
protected:
EnableSharedFromThis() noexcept {}
// 构造函数
EnableSharedFromThis(const EnableSharedFromThis&) noexcept {}
// 拷贝构造函数
EnableSharedFromThis& operator=(const EnableSharedFromThis&) noexcept { return *this; }
~EnableSharedFromThis() {}
private:
mutable WeakPtr<T> _weak_this;
template <typename U>
friend class SharedPtr;
};
可以看到未指向资源的成员变量_weak_this
,SharedFromThis函数weak_ptr中提升返回指向资源的shared_ptr
实际_weak_this
的初始化是在shared_ptr构造函数中完成的,所以使用enable_shared_from_this时,需要外部定义存在一个shared_ptr指向当前对象,如果不定义,会导致_weak_this为空,调用SharedFromThis函数时,会抛bad_weak_ptr异常,和用weak_ptr创建一个shared_ptr时抛的异常一致
shared_ptr构造函数中初始化_weak_this的简化实现代码如下:
cpp
SharedPtr(T* p) : _ptr(p) {
unique_ptr<T> hold(p);
_cntrl = new atomic<int>(1);
hold.release();
__enable_weak_this(p, p);
}
其中主要实现精髓是__enable_weak_this成员函数(初始化了enable_shared_from_this中的_weak_this
),此外使用了unique_ptr先保持资源,防止new时抛出异常,造成内存泄露
接下来可以看__enable_weak_this实现:
- 实现使用了模板,当类继承了EnableSharedFromThis时,实例化第一个模板,初始化EnableSharedFromThis基类中的
_weak_this
- 当类未继承EnableSharedFromThis时,实例化第二个模板,什么都不做
cpp
// 如果继承了EnableSharedFromThis 实例化这个
template <class _Yp, class _OrigPtr>
typename enable_if<is_convertible<_OrigPtr*, const EnableSharedFromThis<_Yp>*>::value,
void>::type
__enable_weak_this(const EnableSharedFromThis<_Yp>* __e, _OrigPtr* __ptr) noexcept {
typedef typename remove_cv<_Yp>::type _RawYp;
if (__e && __e->_weak_this.Expired()) {
__e->_weak_this =
SharedPtr<_RawYp>(*this, const_cast<_RawYp*>(static_cast<const _Yp*>(__ptr)));
}
}
// 没继承EnableSharedFromThis 实例化这个
void __enable_weak_this(...) noexcept { cout << "---__enable_weak_this no op" << endl; }
参考资料
- zhuanlan.zhihu.com/p/416289479
- 《Effective Modern C++》