C++ 基礎之引用計數

智能指針

智能指針是一個類,它對普通指針進行封裝,使智能指針類對象具有普通指針類型一樣的操作。具體而言,複製對象時,副本和原對象都指向同一存儲區域,如果通過一個副本改變其所指的值,則通過另一對象訪問的值也會改變.所不同的是,智能指針能夠對內存進行進行自動管理,避免出現懸垂指針等情況。

引用計數

引用計數是這樣一個技巧,它允許有多個相同值的對象共享這個值的實現。引用計數的使用常有兩個目的:

一旦一個對象通過調用new被分配出來,記錄誰擁有這個對象是很重要的,因為其所有者要負責對它進行delete。但是對象所有者可以有多個,且所有權能夠被傳遞,這就使得內存跟蹤變得困難。引用計數可以跟蹤對象所有權,並能夠自動銷燬對象。節省內存,提高程序運行效率。如何很多對象有相同的值,為這多個相同的值存儲多個副本是很浪費空間的,所以最好做法是讓左右對象都共享同一個值的實現。

智能指針實現乞丐版

智能指針的實現策略有兩種:輔助類與句柄類

<code>#include <iostream>using namespace std;class Point{public: Point(int xVal = 0, int yVal = 0) : x(xVal), y(yVal) {} int getX() const { return x; } int getY() const { return y; } void setX(int xVal) { x = xVal; } void setY(int yVal) { y = yVal; }private: int x, y;};class U_Ptr{private: friend class SmartPtr; U_Ptr(Point *ptr) : p(ptr), count(1) {} ~U_Ptr() { delete p; } int count; Point *p;};class SmartPtr{public: SmartPtr(Point *ptr) : rp(new U_Ptr(ptr)) {} SmartPtr(const SmartPtr &sp) : rp(sp.rp) { ++rp->count; } SmartPtr &operator=(const SmartPtr &rhs) { ++rhs.rp->count; if (--rp->count == 0) delete rp; rp = rhs.rp; return *this; } int getCount() { return rp->count; } ~SmartPtr() { if (--rp->count == 0) delete rp; else cout << "還有" << rp->count << "個指針指向基礎對象" << endl; }private: U_Ptr *rp;};int main(){ //定義一個基礎對象類指針 Point *pa = new Point(10, 20); //定義三個智能指針類對象,對象都指向基礎類對象pa //使用花括號控制三個指針指針的生命期,觀察計數的變化 { SmartPtr sptr1(pa); //此時計數count=1 { SmartPtr sptr2(sptr1); //調用複製構造函數,此時計數為count=2 { SmartPtr sptr3 = sptr1; //調用賦值操作符,此時計數為conut=3 cout << sptr3.getCount() << endl; } //此時count=2 cout << sptr2.getCount() << endl; } //此時count=1; cout << sptr1.getCount() << endl; } //此時count=0;pa對象被delete掉 cout << pa->getX() << endl; // system("pause"); return 0;}/<iostream>/<code>

支持指針操作

<code>#include <iostream>using namespace std;class Point{public: Point(int xVal = 0, int yVal = 0) : x(xVal), y(yVal) {} int getX() const { return x; } int getY() const { return y; } void setX(int xVal) { x = xVal; } void setY(int yVal) { y = yVal; }private: int x, y;};class U_Ptr{private: friend class SmartPtr; U_Ptr(Point *ptr) : p(ptr), count(1) {} ~U_Ptr() { delete p; } int count; Point *p;};class SmartPtr{public: SmartPtr(Point *ptr) : rp(new U_Ptr(ptr)) {} SmartPtr(const SmartPtr &sp) : rp(sp.rp) { ++rp->count; } SmartPtr &operator=(const SmartPtr &rhs) { ++rhs.rp->count; if (--rp->count == 0) delete rp; rp = rhs.rp; return *this; } int getCount() { return rp->count; } ~SmartPtr() { if (--rp->count == 0) delete rp; else cout << "還有" << rp->count << "個指針指向基礎對象" << endl; } Point &operator*() //重載*操作符 { return *(rp->p); } Point *operator->() //重載->操作符 { return rp->p; }private: U_Ptr *rp;};int main(){ //定義一個基礎對象類指針 Point *pa = new Point(10, 20); //定義三個智能指針類對象,對象都指向基礎類對象pa //使用花括號控制三個指針指針的生命期,觀察計數的變化 { SmartPtr sptr1(pa); //此時計數count=1 { SmartPtr sptr2(sptr1); //調用複製構造函數,此時計數為count=2 { SmartPtr sptr3 = sptr1; //調用賦值操作符,此時計數為conut=3 cout << sptr3->getX() << endl; } //此時count=2 cout << sptr2.getCount() << endl; } //此時count=1; cout << sptr1.getCount() << endl; } //此時count=0;pa對象被delete掉 cout << pa->getX() << endl; // system("pause"); return 0;}/<iostream>/<code>

支持模板操作

<code>#include <iostream>using namespace std;template <typename>class SmartPtr;template <typename>class U_Ptr{private: friend class SmartPtr; U_Ptr(T *ptr) : p(ptr), count(1) {} ~U_Ptr() { delete p; } int count; T *p;};template <typename>class SmartPtr{public: SmartPtr(T *ptr) : rp(new U_Ptr(ptr)) {} SmartPtr(const SmartPtr &sp) : rp(sp.rp) { ++rp->count; } SmartPtr &operator=(const SmartPtr &rhs) { ++rhs.rp->count; if (--rp->count == 0) delete rp; rp = rhs.rp; return *this; } int getCount() { return rp->count; } ~SmartPtr() { if (--rp->count == 0) delete rp; else cout << "還有" << rp->count << "個指針指向基礎對象" << endl; } T &operator*() //重載*操作符 { return *(rp->p); } T *operator->() //重載->操作符 { return rp->p; }private: U_Ptr *rp;};int main(){ int *i = new int(2); { SmartPtr ptr1(i); { SmartPtr ptr2(ptr1); { SmartPtr ptr3 = ptr2; cout << *ptr1 << endl; *ptr1 = 20; cout << *ptr2 << endl; } } } return 0;}/<typename>/<typename>/<typename>/<iostream>/<code>

xdl的實現

<code>#include <atomic>#include <utility>class RefCounted{public: explicit RefCounted(int ref = 1) : ref_(ref) {} virtual ~RefCounted() {} void Ref() { ref_++; } void UnRef() { if (--ref_ == 0) { delete this; } } int64_t getRef() { return ref_; }private: std::atomic<int64> ref_;};template <typename>class RefCountedPtr{public: RefCountedPtr() : ptr_(nullptr) {} explicit RefCountedPtr(T *ptr) : ptr_(ptr) { Ref(); } RefCountedPtr(const RefCountedPtr &rptr) : ptr_(rptr.ptr_) { Ref(); } RefCountedPtr(RefCountedPtr &&rptr) : ptr_(rptr.ptr_) { rptr.ptr_ = nullptr; } RefCountedPtr &operator=(T *ptr) { UnRef(); ptr_ = ptr; Ref(); return *this; } RefCountedPtr &operator=(const RefCountedPtr &rptr) { UnRef(); ptr_ = rptr.ptr_; Ref(); return *this; } RefCountedPtr &operator=(RefCountedPtr &&rptr) { std::swap(ptr_, rptr.ptr_); return *this; } ~RefCountedPtr() { if (ptr_ != nullptr) { ptr_->UnRef(); } } std::add_lvalue_reference operator*() const { return *ptr_; } T *operator->() const { return ptr_; } T *get() const { return ptr_; } template <typename...> static RefCountedPtr Create(Targs &&... args) { return RefCountedPtr(new T(std::forward<targs>(args)...), 0); }private: // for RefCountedPtr::Create RefCountedPtr(T *ptr, int x) : ptr_(ptr) { (void)x; } void Ref() { if (ptr_ != nullptr) { ptr_->Ref(); } } void UnRef() { if (ptr_ != nullptr) { ptr_->UnRef(); } } T *ptr_;};/<targs>/<typename...>/<typename>/<int64>/<utility>/<atomic>/<code>

測試用例

<code>#include "xdl_ref_count.h"#include <iostream>#include <unordered>#include <string>using namespace std;class TestObject : public RefCounted { public: std::string test() { std::string res = "testObject here"; return res; }};class TestObjectManger {public: void get(std::string& name) { cout << "get in TestObjectManger " << endl; std::unordered_map<:string refcountedptr="">>::iterator it = test_object_map_.find(name); if (it == test_object_map_.end()) { cout << "not found" << endl; } else { std::cout << it->second->test() << endl; } // return test_object_map_[name]; } void insert(std::string name, RefCountedPtr<testobject> pa) { test_object_map_[name] = pa ; } private: std::unordered_map<:string refcountedptr="">> test_object_map_;};int main(){ TestObject *test = new TestObject(); { std::cout << test->test() << endl; TestObject *test2 = new TestObject(); RefCountedPtr<testobject> test_ptr(test); std::cout << test_ptr->getRef() << endl; RefCountedPtr<testobject> test_ptr2(test); std::cout << test_ptr2->getRef() << endl; test_ptr2 = test2; std::cout << test_ptr2->getRef() << endl; } RefCountedPtr<testobject> test_ptr(test); std::cout << test_ptr->getRef() << endl;}/<testobject>/<testobject>/<testobject>/<testobject>/<string>/<unordered>/<iostream>/<code>

測試腳本:

<code>g++ test_xdl_ref_count.cc -o test_xdl_ref_count/<code>