一、概述
shared_ptr實作了引用計數的功能,在引用計數為0時,自動delete掉管理的對象。
二、實作要點
- shared_ptr需要實作構造對象以及指派時的計數。
- shared_ptr需要實作自身銷毀時的計數減少。
- 需要實作計數為0時自動銷毀管理的對象。
- 需要實作std::move語義。
- 要處理多線程下的計數問題。
三、shared_ptr的簡單實作源碼
#pragma once
#include <memory>
#include <atomic>
using namespace std;
template<class T> class MyRefCount
{
private:
atomic<long> _uses; //atomic使用CPU級的控制,保證多個線程,一個在修改時,其他線程檢視和修改回退。
T* _ptr;
//long weaks; 這個用來處理weak_ptr,本代碼不做實作
void destory()
{
delete _ptr; //計數為0後,調用實際對象的析構函數
}
public:
MyRefCount(T* ptr)
{
_ptr = ptr;
_uses = 1;
}
void incRef()
{
_uses++;
}
void decRef()
{
_uses--;
if (_uses == 0)
{
destory();
}
}
long use_count()
{
return _uses;
}
};
template<class T> class MySharedPtr
{
private:
T* _ptr;
MyRefCount<T>* _refCount;
public:
MySharedPtr()
{
_ptr = nullptr;
_refCount = nullptr;
}
MySharedPtr(T* ptr)
{
this->_ptr = ptr;
_refCount = new MyRefCount<T>(ptr);
}
~MySharedPtr()
{
if (_refCount != nullptr)
{
_refCount->decRef();
_refCount = nullptr;
}
_ptr = nullptr;
}
MySharedPtr(const MySharedPtr<T>& right) //拷貝構造函數
{
if (right._refCount != nullptr)
{
right._refCount->incRef(); //右值被引用次數加1
}
_ptr = right._ptr; //左值用右值的ptr
_refCount = right._refCount; //左值用右值的refcount
}
MySharedPtr(MySharedPtr<T>&& right) //移動構造函數
{
//把右值的歸屬權轉移給左值
_ptr = right._ptr;
_refCount = right._refCount;
right._ptr = nullptr;
right._refCount = nullptr;
}
MySharedPtr<T>& operator=(MySharedPtr<T>& right)
{
right._refCount->incRef();
if (_refCount != nullptr)
{
_refCount->decRef();
}
_ptr = right._ptr;
_refCount = right._refCount;
return (*this);
}
MySharedPtr<T>& operator=(MySharedPtr<T>&& right)
{
MySharedPtr<T> t = std::move(right); //= std::move 會調用移動構造函數,t獲得right的資料所有權,right失去資料所有權
t.swap(*this); //交換t和this,然後t在函數退出時清理掉,會讓原本this指向的對象計數減1
return (*this);
}
void swap(MySharedPtr<T>& t)
{
std::swap(this->_refCount, t._refCount);
std::swap(this->_ptr, t._ptr);
}
T* get() //擷取原生指針
{
return _ptr;
}
T* operator->() //重載指針操作符,實作用MySharedPtr通路T的成員
{
return get();
}
long use_count() //傳回引用的數量
{
return _refCount != nullptr?_refCount->use_count():0;
}
};
class MySharedPtrClass
{
public:
int v;
~MySharedPtrClass()
{
printf("MySharedPtrClass destory\n");
}
};
class MySharedPtrTest
{
private:
void func(MySharedPtr<MySharedPtrClass> mySharedPtr, shared_ptr<MySharedPtrClass> sharedPtr)
{
printf("mySharedPtr use count=%ld, sharedPtr use count=%ld\n", mySharedPtr.use_count(), sharedPtr.use_count());
mySharedPtr->v = 1;
}
public:
void doTest()
{
MySharedPtr<MySharedPtrClass> mySharedPtr(new MySharedPtrClass());
shared_ptr<MySharedPtrClass> sharedPtr(new MySharedPtrClass());
printf("mySharedPtr use count=%ld, sharedPtr use count=%ld\n", mySharedPtr.use_count(),sharedPtr.use_count());
MySharedPtr<MySharedPtrClass> myT = mySharedPtr;
shared_ptr<MySharedPtrClass> t = sharedPtr;
printf("mySharedPtr use count=%ld, sharedPtr use count=%ld\n", mySharedPtr.use_count(), sharedPtr.use_count());
func(mySharedPtr, sharedPtr);
printf("mySharedPtr use count=%ld, sharedPtr use count=%ld\n", mySharedPtr.use_count(), sharedPtr.use_count());
myT = std::move(mySharedPtr);
t = std::move(sharedPtr);
printf("mySharedPtr use count=%ld, sharedPtr use count=%ld\n", mySharedPtr.use_count(), sharedPtr.use_count());
}
};