山寨shared_ptr实现
Counter计数器
- counter里面需要引用计数 一个strong_ptr 一个weak_ptr
- counter里面需要deleter,用于擦没有virtual destructor类的屁股
// count.h
#pragma once
class DeleterBase {
public:
virtual void destroy() = 0; // 擦屁股方法
};
template<class P>
class Deleter : public DeleterBase {
public:
Deleter(P* p) : original_p(p) {}
virtual void destroy() final {
delete original_p;
}
P* original_p; // 原理就是记录原始指针的类型
};
// 下面就是完整的counter
class Count {
public:
template<class Original>
Count(Original* p) : strong_count(1), weak_count(0) {
this->deleter_base = new Deleter<Original>(p);
}
std::atomic<uint64_t> strong_count;
std::atomic<uint64_t> weak_count;
DeleterBase* deleter_base;
};
SharePtr实现
#include "count.h"
template<class T>
class SharePtr {
public:
// 默认构造
SharePtr() : p(nullptr), cb(nullptr) {
}
// 裸指针构造
SharePtr(T* t) : p(t) {
this->cb = new Count(t);
this->p = t;
}
// 同类型复制构造 需要增加计数
// 这个是必须的 否则编译器会生成默认的复制构造函数 导致不会增加计数
SharePtr(const SharePtr<T>& other)
{
if (other) {
this->cb = other.cb;
this->p = other.p;
this->cb->strong_count++;
}else {
::new(this)(SharePtr);
}
}
// 非同类型复制构造 需要增加计数 只能子类构造基类指针
// 如果other是空指针 我们也构造空指针
template<class Other>
SharePtr(const SharePtr<Other>& other)
{
if (other) {
this->cb = other.cb;
this->p = other.p;
this->cb->strong_count++;
}else {
::new(this)(SharePtr);
}
}
// reset操作
// 计数减1 如果强引用计数减到0了 那就析构
// 如果强引用计数减到0了且弱计数也为0 删除cb
void reset() {
if (cb) {
--cb->strong_count;
if (cb->strong_count == 0) {
cb->deleter_base->destroy();
if (cb->weak_count == 1) {
delete cb;
}else {
// 如果有其他wptr拿着指针 但是cb->strong_count == 0了
// 那么他们负责析构cb
cb->weak_count--;
}
}
this->cb = nullptr;
this->p = nullptr;
}
}
// 同类型赋值重载 需要增加计数
SharePtr& operator=(const SharePtr<T>& other) {
this->reset();
this->p = other.p;
this->cb = other.cb;
this->cb->strong_count++;
return *this;
}
// 非同类型赋值重载 需要增加计数 只能子类构造基类指针
template<class Other>
SharePtr& operator=(const SharePtr<Other> &other)
{
this->reset();
this->p = other.p;
this->cb = other.cb;
this->cb->strong_count++;
return *this;
}
///////// 以下是基本操作 ////////
~SharePtr() {
reset();
}
T* operator->() {
return this->p;
}
T& operator*() {
return *this->p;
}
// 方便 if (xxx)
explicit operator bool() const
{
return this->cb && this->cb->strong_count > 0;
}
uint64_t use_count() {
return this->cb->strong_count;
}
T* p;
Count* cb;
};
WeakPtr实现
考虑到循环引用 我们需要加上weak_ptr
#include "count.h"
template<class T>
class WeakPtr {
public:
WeakPtr() : p(nullptr), cb(nullptr) {
}
// 由SharePtr构造WeakPtr
WeakPtr(const SharePtr<T>& t) {
if(t) {
this->p = t.p;
this->cb = t.cb;
this->cb->weak_count++;
}else {
::new(this)(WeakPtr);
}
}
~WeakPtr() {
release();
}
void release() {
if (cb) {
--cb->weak_count;
if (cb->weak_count == 0) {
delete cb;
}
this->p = nullptr;
this->cb = nullptr;
}
}
SharePtr<T> lock() {
if (!cb || cb->strong_count == 0) {
return SharePtr<T>();
}
return SharePtr<T>(*this);
}
friend class SharePtr<T>; // SharePtr<T>需要访问本类的私有成员
private:
T* p;
Count* cb;
};
我们需要往SharedPtr里面添加对于WeakPtr的构造函数
// 先来个前项声明
template<class T> class WeakPtr;
template<class T>
class SharePtr
/// .....
// 为了用weak_ptr的lock(),来生成share_ptr用,需要拷贝构造用
// other有可能是0 strong_count的引用 这里就懒得加判断了
SharePtr(WeakPtr<T>& other)
{
this->p = other.p;
this->cb = other.cb;
this->cb->strong_count++;
}
到此 wptr就完成了
EnableShareFromThis实现
enable_shared_from_this是为了解决在类里面拿自己的shared_ptr的问题
template<class T>
class EnableShareFromThis {
public:
EnableShareFromThis() { }
friend class SharePtr<T>;
SharePtr<T> share_from_this() {
return this->weak_ptr.lock();
}
private:
WeakPtr<T> weak_ptr;
};
初始化问题:
auto p = SharePtr<CLASSNAME>();
SharePtr的构造函数需要构造EnableShareFromThis类
但是并不是所有的CLASSNAME类都继承了EnableShareFromThis类
还是用type_traits解决问题
// 首先加上前向声明
template<class T> class EnableShareFromThis;
template<class T>
class SharePtr
// .....
// 简单地修改一下构造函数即可
SharePtr(T* t) : p(t) {
this->cb = new Count(t);
this->p = t;
if (std::is_base_of<EnableShareFromThis<T>, T>::value) {
t->weak_ptr.p = t;
t->weak_ptr.cb = this->cb;
t->weak_ptr.cb->weak_count++;
}
}
完整代码
#include <type_traits>
template<class T> class WeakPtr;
template<class T> class EnableShareFromThis;
template<class T>
class SharePtr {
public:
SharePtr() : p(nullptr), cb(nullptr) {
}
SharePtr(T* t) : p(t) {
this->cb = new Count(t);
this->p = t;
if (std::is_base_of<EnableShareFromThis<T>, T>::value) {
t->weak_ptr.p = t;
t->weak_ptr.cb = this->cb;
t->weak_ptr.cb->weak_count++;
}
}
// 同类型复制构造 需要增加计数
// 这个是必须的 否则编译器会生成默认的复制构造函数 导致不会增加计数
SharePtr(const SharePtr<T>& other)
{
if (other) {
this->cb = other.cb;
this->p = other.p;
this->cb->strong_count++;
}else {
::new(this)(SharePtr);
}
}
// 非同类型复制构造 需要增加计数 只能子类构造基类指针
// 如果other是空指针 我们也构造空指针
template<class Other>
SharePtr(const SharePtr<Other>& other)
{
if (other) {
this->cb = other.cb;
this->p = other.p;
this->cb->strong_count++;
}else {
::new(this)(SharePtr);
}
}
// reset操作
// 计数减1 如果强引用计数减到0了 那就析构
// 如果强引用计数减到0了且弱计数也为0 删除cb
void reset() {
if (cb) {
--cb->strong_count;
if (cb->strong_count == 0) {
cb->deleter_base->destroy();
if (cb->weak_count == 1) {
delete cb;
}else {
// 如果有其他wptr拿着指针 但是cb->strong_count == 0了
// 那么他们负责析构cb
cb->weak_count--;
}
}
this->cb = nullptr;
this->p = nullptr;
}
}
// 同类型赋值重载 需要增加计数
SharePtr& operator=(const SharePtr<T>& other) {
this->reset();
this->p = other.p;
this->cb = other.cb;
this->cb->strong_count++;
return *this;
}
// 非同类型赋值重载 需要增加计数 只能子类构造基类指针
template<class Other>
SharePtr& operator=(const SharePtr<Other> &other)
{
this->reset();
this->p = other.p;
this->cb = other.cb;
this->cb->strong_count++;
return *this;
}
// WeakPtr构造
SharePtr(WeakPtr<T>& other)
{
this->p = other.p;
this->cb = other.cb;
this->cb->strong_count++;
}
~SharePtr() {
reset();
}
explicit operator bool() const
{
return this->cb && this->cb->strong_count > 0;
}
T* operator->() {
return this->p;
}
T& operator*() {
return *this->p;
}
uint64_t use_count() {
return this->cb->strong_count;
}
T* p;
Count* cb;
};
template<class T>
class EnableShareFromThis {
public:
EnableShareFromThis() { }
friend class SharePtr<T>;
SharePtr<T> share_from_this() {
return this->weak_ptr.lock();
}
private:
WeakPtr<T> weak_ptr;
};
template<class T>
class WeakPtr {
public:
WeakPtr() : p(nullptr), cb(nullptr) {
}
~WeakPtr() {
release();
}
WeakPtr(const SharePtr<T>& t) {
if(t) {
this->p = t.p;
this->cb = t.cb;
this->cb->weak_count++;
}else {
::new(this)(WeakPtr);
}
}
SharePtr<T> lock() {
if (!cb || cb->strong_count == 0) {
return SharePtr<T>();
}
return SharePtr<T>(*this);
}
void release() {
if (cb) {
--cb->weak_count;
if (cb->weak_count == 0) {
delete cb;
}
this->p = nullptr;
this->cb = nullptr;
}
}
friend class SharePtr<T>;
private:
T* p;
Count* cb;
};
测试一下
class Base {
public:
~Base(){
printf("base die\n");
}
};
class Derive : public Base , public EnableShareFromThis<Derive> {
public:
~Derive() {
printf("Derive die\n");
}
};
int main() {
{
auto p1 = SharePtr<Derive>(new Derive());
{
SharePtr<Derive> p2(p1); // 复制构造
SharePtr<Derive> p3;
p3 = p1; // 复制 operator=重载
}
{
SharePtr<Base> pb(p1); // 复制构造 + 转型
SharePtr<Base> pb2;
pb2 = p1; // 复制 operator=重载 + 转型
}
{
WeakPtr<Base> wb(p1);
WeakPtr<Base> wb2;
// wb2 = p1; // 我们还没写这个 懒得写了
}
{
auto p = p1->share_from_this(); // share_from_this
}
/*
{
SharePtr<Base> bp;
bp = p1;
p1.reset(); // reset Derive指针
// reset Base指针
// 引用降为0 擦除原指针 Derive正常析构 导致EnableShareThis析构 导致WeakPtr析构
// 引用变为 strong_count: 0 weak_count: 1
// 最后析构 cb
bp.reset();
}
*/
{
WeakPtr<Derive> wd(p1);
p1.reset(); // reset Derive指针
// 现在strong_count == 0 weak_count == 1
// 退栈析构wd ---> 析构 cb
}
}
return 0;
}