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>