13.2:拷贝控制和资源管理

两种选择:
  • 类的行为像一个值:有自己的状态,拷贝一个像值的对象时,副本和原对象是完全独立的。改变副本不会改变原对象。
  • 类的行为像一个指针:类是共享状态,当拷贝这个对象时,原对象和副本对象使用相同的底层数据,改变副本也会改变原对象。

1.行为像值的类
  拷贝对象,而不是拷贝指针。
  代码如下:
  class HasPtr{
  public:
      HasPtr(const string &s = string()):ps(new string(s)), i(0) {}
      //对ps指向的string,每个HasPtr对象都有自己的拷贝
      HasPtr(const HasPtr &p):ps(new string(*p.ps)), i(p.i) {}
      HasPtr& operator = (const HasPtr&);
      ~HasPtr() { delete ps; }
  private:
      string *ps;
      int i;
  };
 
  HaPtr& HasPtr::operator = (const HasPtr &rhs)
  {
      auto newp = new string(*rhs.ps);  //拷贝底层string
      delete ps;  //释放旧内存
      ps = newp;  //从右侧对象拷贝数据到本对象
      i = rhs.i;
      return *this;  //返回本对象。
  }
  注意要防范自赋值操作的错误。
  错误代码:
  HaPtr& HasPtr::operator = (const HasPtr &rhs)
  {
      delete ps;  //释放对象指向的string
      //但是如果rhs和*this是同一对象,就将从已经释放的内存中拷贝数据
      ps = new string(*(rhs.ps));
      i = rhs.i;
      return *this;  //返回本对象。
  }

2.行为像指针的类
  需要拷贝指针,而不是拷贝指针所指的对象。
  对于共享资源,最好的方法是使用shared_ptr。当时如果希望直接管理资源,最好使用引用计数(使用自定义而非shared_ptr)。
  工作方式如下:
  • 在构造函数中,除了初始化对象外,还要创建一个引用计数,来记录共享状态。初始化时只有一个对象,引用计数初始化为1.
  • 拷贝构造函数不分配新的计数器,而是拷贝给定对象的数据成员,包括计数器。并且要递增共享的计数器。
  • 析构函数递减计数器,当计数器变为0时,析构函数就可以释放成员。
  • 拷贝赋值运算符要递增右侧运算对象的计数器,递减左侧对象的计数器。如果左侧运算对象计数器为0,拷贝赋值运算符就必须销毁此对象的状态。
  为了更新引用计数,将计数器保存在动态内存中,当创建对象,分配一个新的计数器,拷贝或赋值对象时,拷贝指向计数器的指针。
代码如下:
class HasPtr{
public:
    //构造函数分配新的string和新的计数器1
    HasPtr(const string &s = string()):ps(new string(s)),i(0),use(new size_t(1)){}
    //拷贝构造函数拷贝三个成员,并递增计数器
    HasPtr(const HasPtr &p):ps(p.ps), i(p.i), use(p.use) { ++*use; }
    HasPtr& operator = (const HasPtr&);
    ~HasPtr();
private:
    string *ps;
    int i;
    size_t *use; //计数器,记录共享*ps的成员
};
 
HasPtr& HasPtr::operator = (const HasPtr &rhs)
{
    ++*rhs.use;  //递增右侧运算对象的引用计数
    --*use; //递减本对象的引用计数
    if(*use == 0)
    {
        delete ps; //释放对象
        delete use; //释放计数器
    }
    //拷贝rhs对象
    ps = rhs.ps;
    i = rhs.i;
    use = rhs.use;
    return *this;
}
 
HasPtr::~HasPtr()
{
    --*use; //递减对象计数器
    if(*use == 0)
    {
        delete ps; //释放对象
        delete use; //释放计数器
    }
}

转载于:https://www.cnblogs.com/CoderZSL/p/7617136.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值