ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

拷贝控制和资源管理

2020-03-15 12:04:11  阅读:208  来源: 互联网

标签:Hasptr 控制 string ps 对象 计数器 拷贝 资源管理


类的行为可以像一个值或指针:

类的行为像一个值,意味着它应该也有自己的状态。当我们拷贝一个像值得对象时,副本与原对象是独立的,改变副本不会对原对象有任何影响,反之亦然。

类的行为像指针,将共享状态,拷贝这样的一个类的对象时,副本和原对象使用相同的底层数据,改变副本也会改变原对象,反之亦然。

行为像值的类

提供类值的行为,对于类管理的资源,每个对象都应该拥有一份自己的拷贝。

class Hasptr{
public:
    Hasptr(const std::string &s=std::string()):ps(new std::string(s)),i(0){}
    Hasptr(const Hasptr &p):ps(new std::string(*p.ps)),i(p.i){}
    Hasptr& operator=(const Hasptr&);
    ~Hasptr(){delete ps;}
private:
    std::string *ps;
    int i;
}

类值拷贝赋值运算符

赋值运算符组合了析构函数和构造函数的操作:

  • 类似析构函数,赋值操作会销毁左侧运算对象的值;
  • 类似拷贝构造函数,赋值操作会从右侧对象拷贝数据。

需要注意的是:

  • 如果将一个对象赋予自身,赋值运算符必须能正常工作;
  • 异常安全,即当异常发生时,能将左侧运算对象置于一个有意义的状态。
Hasptr& Hasptr::operator = (const Hasptr &rhs)
{
    auto newp =  new string(*rhs.ps);   //拷贝底层的string
    delete ps;      //释放旧内存
    ps = newp;      //右侧对象拷贝数据到本对象
    i = rhs.i;
    return *this;   //返回本对象
}

行为像指针的类

引用计数

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

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

计数器不能是 Hasptr 对象的成员:

Hasptr p1("Hiya");
Hasptr p2(p1);  
Hasptr p3(p1);  //p1,p2,p3指向相同的string

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

解决办法是将计数器保存在动态内存中,当创建一个对象时,也分配一个新的计数器,当拷贝或赋值对象时,拷贝指向计数器的指针,使用此方法可以保证副本和原对象指向相同的计数器。

定义一个使用引用计数的类

class Hasptr
{
public:
    Hasptr(const std::string &s = std::string()):ps(new std::string(s),i(0),use(new std::size_t(1))){}
    Hasptr(const Hasptr &p):ps(p.ps),i(p.i),use(p.use){++*use};
    Hasptr& operator=(const Hasptr&);
    ~Hasptr();
private:
    std::string *ps;
    int i;
    std::size_t *use;
}

析构函数需要检查引用计数是否为0:

Hasptr ::~Hasptr()
{
    if(--*use == 0){
        delete ps;
        delete use;
    }
}

拷贝赋值运算符:

Hasptr& Hasptr::operator=(const Hasptr& rhs)
{
    ++*rhs.use;     //递增右侧对象的引用计数
    if(--*use == 0) //递减和检测本对象的引用计数
    {
        delete ps;
        delete use;
    }
    
    ps = rhs.ps;
    i = rhs.i;
    use = rhs.use;
    
    return *this;
}

标签:Hasptr,控制,string,ps,对象,计数器,拷贝,资源管理
来源: https://www.cnblogs.com/xiaojianliu/p/12496728.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有