在說weak_ptr之前,需要回憶一下shared_ptr的知識。
shared_ptr是采用引用計數的智能指針,多個shared_ptr執行個體可以指向同一個動态對象,并維護了一個共享的引用計數器。對于引用計數發實作的計數,總是避免不了循環引用的問題。
如下執行個體:
class Child;
class Parent
{
public:
shared_ptr<Child> child;
Parent() { cout << "Creat Parent" << endl; }
~Parent() { cout << "Destory Parent" << endl; }
void hi() const{ cout << "hello" << endl; }
};
class Child
{
public:
shared_ptr<Parent> parent;
Child() { cout << "Creat Child" << endl; }
~Child() { cout << "Destory Child" << endl; }
};
int main()
{
shared_ptr<Parent> par(new Parent());
shared_ptr<Child> pch(new Child());
par->child = pch;
pch->parent = par;
pch->parent->hi();
return 0;
}
結果:
上面代碼的運作結果很明顯可以看出來沒有調用Parent和Child的析構函數,這是因為Parent和Chlid的對象内部,具有各自指向對方的shared_ptr,加上par和pch這兩個shared_ptr,說明每個對象的引用計數都是2。當程式退出時,即使par和pch被銷毀,也僅僅是導緻引用計數變為1,是以并未銷毀Parent和Child。
為了解決上面這樣的問題,C++11引入了weak_ptr,來打破這種循環。
1、weak_ptr
weak_ptr是為了配合shared_ptr而引入的一種智能指針,它指向一個由shared_ptr管理的對象而不影響所指對象的生命周期,也就是将一個weak_ptr綁定到一個shared_ptr不會改變shared_ptr的引用計數。
無論是否有weak_ptr指向,一旦最後一個指向對象的shared_ptr被銷毀,對象就會被釋放。
2、weak_ptr的使用
- weak_ptr的建立:
int main()
{
shared_ptr<int> sp(new int(5));
cout << "建立前sp的引用計數" << sp.use_count() << endl;
weak_ptr<int> wp(sp);
cout << "建立後sp的引用計數" << sp.use_count() << endl;
return 0;
}
結果:
-
判斷weak_ptr對象是否存在
因為weak_ptr并不改變其所共享的shared_ptr執行個體的引用計數,那麼weak_ptr所指向的對象可能已經被釋放了,此時,我們就不能使用weak_ptr直接通路對象。
c++中提供了lock函數來實作該功能:如果對象存在,lock()函數傳回一個指向該對象的shared_ptr,否則傳回一個空的shared_ptr。
#include <iostream>
using namespace std;
class Object
{
private:
int value;
public:
Object(int x = 0) :value(x) { cout << "Object Constructor" << endl; }
~Object() { cout << "Object Destructor" << endl; }
int GerValue() const { return value; }
};
int main()
{
shared_ptr<Object> sp(new Object(10));
weak_ptr<Object> wp(sp);
if (shared_ptr<Object> pa = wp.lock())
{
cout << pa->GerValue() << endl;
}
else
{
//expired函數判斷所指對象是否已經被銷毀
cout << wp.expired() << endl;
cout << "wp 引用的對象為空" << endl;
}
return 0;
}
- weak_ptr并沒有重載operator->和operator*操作符,是以不可直接通過weak_ptr使用對象,典型的做法是調用其lock函數來獲得shared_ptr示例,進而通路原始對象。
3、weak_ptr函數的仿寫
template<typename T>
class RefCnt
{
private:
T* mPtr;
std::atomic<int> mCnt_s;
std::atomic<int> mCnt_w;
public:
RefCnt(T* ptr = nullptr) :mPtr(ptr)
{
if (mPtr != nullptr)
{
mCnt_s = 1;
mCnt_w = 1;
}
}
int load_s() const { return mCnt_s.load(); }
int load_w() const { return mCnt_w.load(); }
void addRef_w()
{
mCnt_w++;
}
int delRef_w()
{
return --mCnt_w;
}
void addRef_s()
{
mCnt_s++;
}
int delRef_s()
{
return --mCnt_s;
}
~RefCnt() {}
};
template<typename T>
class MyDeletor
{
public:
void operator()(T* ptr) const
{
delete ptr;
}
};
template<typename T> class weak_ptr;
template<typename T,typename Deletor=MyDeletor<T>>
class shared_ptr
{
public:
typedef T* pointer;
typedef T element_type;
typedef Deletor delete_type;
delete_type get_deleter()
{
return delete_type();
}
public:
shared_ptr(T* ptr = nullptr) : mPtr(ptr)
{
mpRefCnt = new RefCnt<T>(mPtr);
}
shared_ptr(const shared_ptr<T>& src) :mPtr(src.mPtr), mpRefCnt(src.mpRefCnt)
{
mpRefCnt->addRef_s();
}
shared_ptr& operator=(const shared_ptr<T>& src)
{
if (src == this)
{
return *this;
}
if (0 == mpRefCnt->delRef_s())
{
get_deleter()(mPtr);
delete mpRefCnt;
mPtr = nullptr;
mpRefCnt = nullptr;
}
mPtr = src.mPtr;
mpRefCnt = src.mpRefCnt;
mpRefCnt->addRef_s();
return *this;
}
~shared_ptr()
{
if (0 == mpRefCnt->delRef_s())
{
get_deleter()(mPtr);
delete mpRefCnt;
}
mPtr = nullptr;
mpRefCnt = nullptr;
}
T* get()const { return mPtr; }
T& operator*()const { return *get(); }
T* operator->()const { return get(); }
long use_count() const { return mpRefCnt->load_s(); }
void reset(T* p = nullptr)
{
if (0 == mpRefCnt->delRef_s())
{
get_deleter()(mPtr);
delete mpRefCnt;
}
mPtr = p;
mpRefCnt = new RefCnt<T>(mPtr);
}
operator bool()const
{
return get() != nullptr;
}
bool unique()const
{
if (mPtr != nullptr && use_count() == 1)
{
return true;
}
return false;
}
shared_ptr(const weak_ptr<T>& _w)
{
mPtr = _w.mPtr;
_w.mpRefCnt->addRef_s();
mpRefCnt = _w.mpRefCnt;
}
friend class weak_ptr<T>;
private:
T* mPtr;
RefCnt<T>* mpRefCnt;
};
template<class T>
class weak_ptr
{
public: //給出預設構造和拷貝構造,其中拷貝構造不能有從原始指針進行構造
weak_ptr() :mPtr(nullptr), mpRefCnt(nullptr) {};
weak_ptr(shared_ptr<T>& s) :mPtr(s.mPtr), mpRefCnt(s.mpRefCnt)
{
mpRefCnt->addRef_w();
}
weak_ptr(weak_ptr<T>& w) :mPtr(w.mPtr), mpRefCnt(w.mpRefCnt)
{
mpRefCnt->addRef_w();
}
~weak_ptr()
{
release();
}
weak_ptr<T>& operator=(const weak_ptr<T>& w)
{
if (this != &w)
{
release();
mpRefCnt = w.mpRefCnt;
mpRefCnt->addRef_w();
mPtr = w.mPtr;
}
return *this;
}
weak_ptr& operator=(const shared_ptr<T>& s)
{
release();
mpRefCnt = s.mpRefCnt;
mpRefCnt->addRef_w();
mPtr = s.mPtr;
return *this;
}
//通過調用lock()方法,檢查對象是否存在,若存在,則傳回一個指向共享對象的shared_ptr.
shared_ptr<T> lock() const
{
return shared_ptr<T>(*this);
}
int use_count() const
{
return mpRefCnt->load_w();
}
//判斷指向該指針的對象的shared_ptr是否為nullptr,即就是所指對象是否被銷毀
bool expired() const
{
if (mpRefCnt)
{
return mpRefCnt->load_s() == 0;
}
return true;
}
friend class shared_ptr<T>;//友善weak_ptr與share_ptr設定引用計數和指派
protected:
void release()
{
if (mpRefCnt != nullptr)
{
mpRefCnt->delRef_w();
if (mpRefCnt->load_s() == 0 && mpRefCnt->delRef_w() == 0)
{
delete mpRefCnt;
}
mpRefCnt = nullptr;
}
}
private:
T* mPtr;
RefCnt<T>* mpRefCnt;
};