zoukankan      html  css  js  c++  java
  • c/c++ 引用计数

      记录一下,希望以后会用到。

      假若我们有一个类的成员变量需要共享,希望在使用时保留,没有用到时就delete掉,那要怎么设计?

      假设我们有共享数据share_data,对象A,B,C有指向该share_data,如果我们只是在析构函数中单方面地释放关联的share_data,比如A不再需要share_data,并且单方面释放了share_data,那会造成一个问题:B和C还要用share_data呢,但A却把它释放了。因此只有当最后一个指向share_data的对象销毁时,share_data才可以释放。

      引用计数可以解决这样的问题。它的思想是对share_data进行计数,当有对象指向它时,计数加一,当对象不再指向时就计数减一,当计数为0时,就释放share_data。

      若果用C/C++,要怎样设计?

      引用计数的工作方式如下:

    • 除了初始化对象外,每个构造函数(拷贝构造函数除外)还要创建一个引用计数器,用来记录有多少对象与正在创建的对象共享状态。当我们创建一个对象时,只有一个对象共享状态,因此将计数器初始化为1.
    • 拷贝构造函数不分配新的计数器,而是拷贝给定对象的数据成员,包括计数器。拷贝构造函数递增共享的计数器,指出给定对象的状态又被一个新用户所共享。
    • 析构函数递减计数器,指出共享状态的用户又少了一个。如果计数器变为0,则下析构函数释放状态。
    • 拷贝赋值运算符递增右侧运算对象的计数器,递减左侧运算对象的计数器。如果左侧运算对象的计数器变为0,意味着它的共享状态没有用户了,拷贝赋值运算符就必须销毁状态。

     从上述的描述中,我们必须把计数器也共享了,不能直接作为对象的成员。以下例子说明原因。

    Test p1("123");
    Test p2(p1);    // p1和p2都指向相同的string    
    Test p3(p1);    // p1、p2和p3都指向相同的string

      如果引用计数器保存在每个对象中,当创建p3时可以递增p1中的计数器并将其拷贝到p3,但要如何更新p2中的计数器?

      因此我们需要把共享数据和计数器保存到动态内存中。当拷贝或复制对象时,我们拷贝指向计数器的指针,使得副本和原对象都会指向相同相同的计数器。

      以下给出实现代码:

     1 class test {
     2 public:
     3         // 构造函数分配新的string和新的计数器,将计数器置为1
     4     test(const string& s = string()) :
     5         ps(new string(s)), i(0), use(new size_t(1)) {}
     6 
     7         // 拷贝构造函数拷贝所有数据成员,并递增计数器
     8     test(const test& p) :
     9         ps(p.ps), i(p.i), use(p.use) {
    10         ++*use;
    11     }
    12 
    13     test& operator = (const test&);
    14 
    15     ~test();
    16 
    17 private:
    18     string* ps;
    19     int i;
    20     size_t* use;    // 用来记录有多少个对象共享*ps的成员
    21 };
    22 
    23 test::~test() {
    24     if (--*use == 0) {     //  如果引用计数变为0
    25         delete ps;          // 释放string内存
    26         delete use;        // 释放计数器内存
    27     }
    28 }
    29 
    30 test& test::operator=(const test& rhs) {
    31     ++*rhs.use;                // 递增右侧运算对象的引用计数
    32     if (--*use == 0) {        // 递减本对象的引用计数
    33         delete ps;             // 如果没有其他用户
    34         delete use;           // 释放本对象分配的成员
    35     }
    36 
    37     use = rhs.use;              // 拷贝数据
    38     i = rhs.i;
    39     ps = rhs.ps;
    40 
    41     return *this;                  // 返回本对象
    42 }
    43     
  • 相关阅读:
    ElasticSearch(7.13.1) 作为服务启动(Windows)
    ElasticSearch(7.13.1) 安装与命令行启动
    Spring Boot 监听器 通过Session监听在线人数
    layui 弹出层icon
    Spring Boot 定时器 系统时间测试
    Spring Boot 拦截器
    Tomcat部署
    SpringBoot学习之整合Swagger
    浅谈Mybatis持久化框架在Spring、SSM、SpringBoot整合的演进及简化过程
    SpringBoot学习之整合Druid的简单应用
  • 原文地址:https://www.cnblogs.com/IamTing/p/4870091.html
Copyright © 2011-2022 走看看