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> 

測試腳本:

C++ 基礎之引用計數

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


分享到:


相關文章: