C++ Primer第五版笔记——拷贝控制和资源管理

本文探讨了如何通过定义拷贝操作使类表现得像值或指针,并介绍了引用计数的概念及其实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

可以通过定义拷贝操作来使得一个类的行为是像一个值还是像一个指针,像一个值表示拷贝对象时,副本和源对象是分别独立的的,改变其中任意一个都不会对另一个造成影响;像一个指针表示拷贝时副本和源对象共享底层的数据,改变其中任意一个都会对另一个造成影响。比如标准库容器和string类的行为像是一个值,shared_ptr类行为像是一个指针,IO类型和ununique_ptr不允许拷贝和赋值,因此他们的行为既不像值也不像指针。
行为像值的类:
意味着每个对象都有自己的资源,都拥有zi一份自己的拷贝。如在面试经常遇到的自定义string类的题:

https://www.nowcoder.com/ta/review-c/review?tpId=22&tqId=21065&query=&asc=true&order=&page=16

定义行为像指针的类:
对于类似指针的类,需要为其定义拷贝构造函数和拷贝赋值运算符,拷贝的是指针本身,而不是它指向的对象。令一个类展现类似指针的行为最好的方法是使用智能指针shared_ptr来管理类中的资源。
但有时我们希望直接管理资源。在这种情况上,使用引用计数就很有用了。
引用计数:
引用计数的工作方式如下:
1.除了初始化对象外,每个构造函数(拷贝构造函数除外)还要创建一个引用计数,用来有多少个对象与正在创建的对象共享状态。当创建第一个对象时,引用计数初始化为1;
2.拷贝构造函数不分配新的计数器,而是拷贝给定对象的数据成员,包括计数器。拷贝构造函数递增共享的计数器,指出给定对象的状态又被一个新用户共享;
3.析构函数递减计数器,如果计数器为0,则析构函数释放状态;
4.拷贝赋值运算符递增右侧运算对象的计数器,递减左侧运算对象的计数器,如果左侧对象的计数器为0了,就销毁其状态。
问题是怎么控制每个对象中的计数器状态,一种方法是将计数器放在动态内存中:

class HasPtr{
public:
    //构造函数分配新的string和新的计数器
    HasPtr(const string& s = string()):
        ps(new string(s),i(0),use(new size_t(1)));
    //拷贝构造函数递增计数器
    HasPtr(const HasPtr& p):
        ps(p.ps),use(p.use){
        *use++;
    }
    //拷贝赋值运算符
    HasPtr& operator=(const HasPtr&);

    //析构函数递减计数器,为0时释放
    ~HasPtr(){
        if(--*use == 0){
            delete ps;          //释放string内存
            delete use;         //释放计数器内存
        }
    }
private:
    string* ps;
    size_t* use;        
};

HasPtr& HasPtr::operator=(const HasPtr& rhs){
    ++*rhs.use;                   //递增右侧对象引用计数
    if(--*use == 0){              //递减左侧对象引用计数
        delete ps;
        delete use;
    }
    ps = rhs.ps;                  //拷贝数据
    use = rhs.use;
    return *this;                 //返回本对象
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值