《C++ Primer 第5版》-13.2拷贝控制和资源管理-康奈尔笔记

13.2.0拷贝控制和资源管理

管理类外的资源的类必须定义拷贝控制成员。需要确定此类型对象的拷贝语义,有让类看起来像一个值或者一个指针

  1. 类的行为像一个值,意味着它应该也有自己的状态。拷贝一个像值的对象时,副本和原对象是完全独立的。改变副本不会对原对象有任何影响
  2. 类的行为像指针,拷贝一个这种类的对象时,副本和原对象使用相同的底层数据。改变副本也会改变原对象

如:

string类的行为像一个值

Shared_ptr类的行为像一个指针

IO类型和unique_ptr不允许拷贝或赋值,他们的行为既不像值也不像指针

13.2.1行为像值的类

  1. 行为像值的类
  2. 类值拷贝赋值运算符

HasPtr(const HasPtr &p):

Ps(new std::string(*p.ps)),i(p.i){}

Auto newp = rhs;

HasPtr&

HasPtr::operator=(const HasPtr &rhs)

{delete ps;

Ps = new string(*(rhs.ps));

I=rhs.i;

Return *this;}

1. 行为像值的类

1)每个对象都应该拥有一份自己的拷贝

如:类中有一个string的指针ps,

在拷贝构造函数需要完成string的拷贝,而不是拷贝指针

在析构函数来释放string

在拷贝赋值运算符来释放当前的string,并从右侧运算对象拷贝string

2. 类值拷贝赋值运算符

1)组合了析构函数和构造函数的操作

关键概念:赋值运算符

1)如果将一个对象赋予它的自身,赋值运算符必须能正确工作

2)大多数赋值运算符组合了析构函数和拷贝构造函数的工作

好的模式写法是:先将右侧运算对象拷贝到一个局部临时对象中。再销毁左侧运算符对象

Note:特别是对象赋予它的自身,如果先销毁左侧对象,那么右侧对象也跟着销毁,所以一定先要保存右侧运算对象

13.2.2定义行为像指针的类

  1. 定义行为像指针的类
  2. 引用计数
  3. 定义一个使用引用计数的类
  4. 类指针的拷贝成员 篡改 引用计数

class HasPtr {

public:

    HasPtr(const string &s = string()) :

         pss(new string(s)), i(0),use(new size_t(1)) {}

    HasPtr(const HasPtr& hp):pss(hp.pss),i(hp.i),use(hp.use){

         ++*use;

    }

HasPtr& operator=(const HasPtr&);

    ~HasPtr() {

         if (--*use == 0) {

             delete use;

             delete pss;

         }

    }

private:

    std::string *pss;

    int i;

    std::size_t* use;

};

HasPtr& HasPtr::operator=(const HasPtr& rhs)

{

    ++(*rhs.use);

    if (--*use == 0) {

         delete use;

         delete pss;

    }

    i = rhs.i;

    use = rhs.use;

    pss = rhs.pss;

    return *this;

}

1. 定义行为像指针的类

1)需要为其定义拷贝构造函数和拷贝赋值运算符,拷贝指针成员本身而不是它指向的string

2)需要自定义析构函数来释放接受string的内存,但是在本例中像指针的类中,需要判断最后一个指向string的类销毁时它才可以释放string

3)让一个类像指针可以用shared_ptr来管理类中的指针资源,但是我们希望自己直接管理资源,可以使用引用计数,也是动态分配的资源。

2. 引用计数

1)引用计数,记录有多少个对象与正在创建的对象共享状态,创建一个对象时初始化为1

2)拷贝构造函数不分配新的计数器,而是拷贝给定对象的数据成员,包括计数器。递增共享的计数器

3)析构函数,递减计数器,若计数器为0,析构函数释放状态

4)拷贝赋值运算符,递增右侧运算符对象的计数器,递减左侧运算对象的计数器。

需要将计数器保存在动态内存中。拷贝或赋值对象时,我们拷贝指向计数器的指针,这样副本和原对象都会指向相同的计数器。

HasPtr p1(“hi”);

HasPtr p2(p1);

HasPtr p3(p1);

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

1)如上代码

4. 类指针的拷贝成员 篡改 引用计数

1)Ps(s),user(user){++*use;}

2)析构函数判断是否计数为0来删除

3)拷贝赋值运算符需要执行拷贝构造函数与析构函数的工作,递增右侧递减左侧

4)拷贝赋值运算符还需要处理自赋值。先递增rhs中的计数,再递减左侧运算对象的,因为这两个总要执行这个操作,需按照这个顺序就没问题,这样就保证自赋值没问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘建杰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值