基于引用计数的内存管理

引用计数原则

  • 对象的初始引用计数是1。
  • 当引用被创建或者拷贝,引用计数加1。
  • 当对象的引用被销毁或者重新赋值,对象的引用计数减1。
  • 当引用计数减为0时,对象被销毁。
  • 多线程场景下,引用计数的增减应当是原子操作。

scoped_refptr和RefCountedObject

scoped_refptr

template <class T>
class scoped_refptr {
 public:
  //1.默认构造函数
  scoped_refptr() : ptr_(nullptr) {}

  //2.构造函数
  scoped_refptr(T* p) : ptr_(p) {
    if (ptr_)
      ptr_->AddRef();
  }

  //3、拷贝构造函数
  scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) {
    if (ptr_)
      ptr_->AddRef();
  }

  //4、带隐式类型转换的拷贝构造函数
  template <typename U>
  scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) {
    if (ptr_)
      ptr_->AddRef();
  }

  //5、Move构造函数.
  scoped_refptr(scoped_refptr<T>&& r) : ptr_(r.release()) {}

  //6、带隐式类型转换的Move构造函数.
  template <typename U>
  scoped_refptr(scoped_refptr<U>&& r) : ptr_(r.release()) {}

  //7、析构函数
  ~scoped_refptr() {
    if (ptr_)
      ptr_->Release();
  }

  //8、获取原始指针
  T* get() const { return ptr_; }
  //9、重载*
  operator T*() const { return ptr_; }
  //10、重载->
  T* operator->() const { return ptr_; }

  //11、释放指针所有权,返回值是该对象当前保存的指针。该方法返回后,此对象不再拥有之前的对象,而是拥有一个空指针。
  T* release() {
    T* retVal = ptr_;
    ptr_ = nullptr;
    return retVal;
  }

  //12、赋值函数
  scoped_refptr<T>& operator=(T* p) {
    // AddRef first so that self assignment should work
    if (p)
      p->AddRef();
    if (ptr_ )
      ptr_ ->Release();
    ptr_ = p;
    return *this;
  }
  //13、赋值函数
  scoped_refptr<T>& operator=(const scoped_refptr<T>& r) {
    return *this = r.ptr_;
  }
  //14、带隐式类型转换的赋值函数
  template <typename U>
  scoped_refptr<T>& operator=(const scoped_refptr<U>& r) {
    return *this = r.get();
  }
  //15、Move赋值
  scoped_refptr<T>& operator=(scoped_refptr<T>&& r) {
    scoped_refptr<T>(std::move(r)).swap(*this);
    return *this;
  }
  //16、带隐式类型转换的Move赋值
  template <typename U>
  scoped_refptr<T>& operator=(scoped_refptr<U>&& r) {
    scoped_refptr<T>(std::move(r)).swap(*this);
    return *this;
  }

  //17、swap
  void swap(T** pp) {
    T* p = ptr_;
    ptr_ = *pp;
    *pp = p;
  }

  //18、swap
  void swap(scoped_refptr<T>& r) {
    swap(&r.ptr_);
  }

 protected:
  T* ptr_;
};

scoped_refptr实现了基于引用计数的内存管理,实际使用中同RefCountedObject配合来实现对指针对象的内存管理。

RefCountedObject

class RefCountInterface {
 public:
  virtual int AddRef() const = 0;
  virtual int Release() const = 0;

 protected:
  virtual ~RefCountInterface() {}
};

RefCountInterface定义引用计数接口

template <class T>
class RefCountedObject : public T {
 public:
  RefCountedObject() {}

  template <class P0>
  explicit RefCountedObject(P0&& p0) : T(std::forward<P0>(p0)) {}

  template <class P0, class P1, class... Args>
  RefCountedObject(P0&& p0, P1&& p1, Args&&... args)
      : T(std::forward<P0>(p0),
          std::forward<P1>(p1),
          std::forward<Args>(args)...) {}

  virtual int AddRef() const { return AtomicOps::Increment(&ref_count_); }

  virtual int Release() const {
    int count = AtomicOps::Decrement(&ref_count_);
    if (!count) {
      delete this;
    }
    return count;
  }

  virtual bool HasOneRef() const {
    return AtomicOps::AcquireLoad(&ref_count_) == 1;
  }

 protected:
  virtual ~RefCountedObject() {}

  mutable volatile int ref_count_ = 0;
};

RefCountedObject实现基于原子锁的引用计数管理。

优点:

1.线程安全的引用计数。
2.析构函数是protected,避免显式delete。

示例

class PeerConnectionFactoryInterface : public RefCountInterface {
public:
    virtual void Show() = 0;
};

class PeerConnectionFactory : public PeerConnectionFactoryInterface {
public:
    virtual void Show() override {  }
};

class PeerConnectionSubFactory : public PeerConnectionFactory {
public:
    virtual void Show() override  {  }
};

scoped_refptr

//1、默认构造函数
scoped_refptr<PeerConnectionFactory> pc_factory_def;

//2、构造函数
scoped_refptr<PeerConnectionFactory> pc_factory(
  new RefCountedObject<PeerConnectionFactory>());

//3、拷贝构造函数
scoped_refptr<PeerConnectionFactory> pc_factory2(pc_factory);

//4、带隐式类型转换的拷贝构造函数
scoped_refptr<PeerConnectionSubFactory> pc_sub_factory(new RefCountedObject<PeerConnectionSubFactory>());
scoped_refptr<PeerConnectionFactory> pc_factory3(pc_sub_factory);

//5、Move构造函数.
scoped_refptr<PeerConnectionFactory> pc_factory4(std::move(pc_factory3));

//6、带隐式类型转换的Move构造函数.
scoped_refptr<PeerConnectionFactory> pc_factory5(std::move(pc_sub_factory));

//8、获取原始指针
pc_factory5.get()->Show();
//9、重载*
(*pc_factory5).Show();
//10、重载->
pc_factory5->Show();

//11、释放指针所有权
PeerConnectionFactory* p = pc_factory5.release();


//12、赋值函数
scoped_refptr<PeerConnectionFactory> pc_factory6 = new RefCountedObject<PeerConnectionFactory>();
//13、赋值函数
pc_factory_def = pc_factory6;
//14、带隐式类型转换的赋值函数
scoped_refptr<PeerConnectionSubFactory> pc_factory8 = new RefCountedObject<PeerConnectionSubFactory>();
pc_factory_def = pc_factory8;
//15、Move赋值
pc_factory_def = std::move(pc_factory6);
//16、带隐式类型转换的Move赋值
pc_factory_def = std::move(pc_factory8);
//18、swap,会调用17
pc_factory.swap(pc_factory_def);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • 内存管理的必要性: 内存泄漏:程序未能释放已经不再使用的内存叫内存泄漏。 悬垂指针(野指针):指针指向已经被释放或...
    陈_振阅读 472评论 0 0
  • 内存管理 简述OC中内存管理机制。与retain配对使用的方法是dealloc还是release,为什么?需要与a...
    丶逐渐阅读 1,946评论 1 16
  • 内存管理是程序在运行时分配内存、使用内存,并在程序完成时释放内存的过程。在Objective-C中,也被看作是在众...
    蹲瓜阅读 2,991评论 1 8
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,169评论 11 349
  • 这世间的所有自然现象,社会现象, 都是有迹可寻,又无计可施的。 穷人与富人不可能存在物质平等与概率平等的绝对关系,...
    可乐薄荷丶阅读 202评论 0 1