《EffectiveC++》读书笔记(2):构造/析构/赋值运算|每日快报
时间:2023-06-17 11:20:47来源:面包芯语

点击上方“C语言与CPP编程”,选择“关注/置顶/星标公众号”

干货福利,第一时间送达!最近有小伙伴说没有收到当天的文章推送,这是因为微信改了推送机制,确实会一部分有小伙伴刷不到当天的文章,一些比较实用的知识和信息,错过了就是错过了。所以建议大家加个星标⭐️,就能第一时间收到推送了。

小伙伴们大家好,我是飞宇。


(资料图)

今天继续更新《Effective C++》和《C++并发编程实战》的读书笔记,下面是已经更新过的内容:

《C++并发编程实战》读书笔记(1):并发、线程管控

《C++并发编程实战》读书笔记(2):并发操作的同步

《Effective C++》读书笔记(1):让自己习惯C++

条款5、了解C++默认编写并调用哪些函数

通常情况下,如果代码中没有声明构造函数、拷贝构造函数、拷贝运算符、析构函数,编译器会在需要时创建他们,但这往往只能满足编译器的需求,很可能无法满足程序的需求。

实际的生成规则复杂一些,可以查阅cppreference。

编译器生成的构造函数/析构函数是只是调用基类和非静态成员变量的构造函数/析构函数;生成的析构函数是非虚的,除非基类有虚析构函数。

至于生成的拷贝构造函数和拷贝操作符只是单纯将每个非静态成员变量拷贝;有const成员或者引用成员时,以及基类拒绝拷贝操作符时,默认生成的拷贝操作符没有意义,必须自己定义。

条款6、若不想使用编译器自动生成的函数,就该明确拒绝

很多时候,你并不希望某些类被拷贝,而仅仅不实现拷贝构造/拷贝运算符是不够的,因为编译器可能会自行生成。

为此,可以把拷贝构造/拷贝运算符声明为"=delete",或者声明为private(后者较为过时)。

事实上,对于析构函数中需要释放资源的类,为了防止内存问题,除非真的需要拷贝功能,否则最好都禁止拷贝。

可以让它们继承上面的类,即可禁止编译器生成拷贝操作:编译器试图为它们生成拷贝构造/拷贝运算符时会尝试调用基类Uncopyable的对应操作,而这会被拒绝。

条款7、为多态基类声明virtual析构函数

C++中多态性质体现于虚函数:基类指针或引用调用虚函数时会检查指向的对象是基类还是派生类,再调用对应的函数。其具体实现这里不再赘述。

当这样的一个指向派生类的基类指针析构时,如果析构函数不是虚函数,则直接调用基类的析构函数,那么派生类获取的资源未释放,则会造成内存泄漏。

而当析构函数是虚函数时则先调用对应的派生类析构函数,再调用基类析构函数,资源全部释放。

不过这种操作只有在基类是多态用途时才需要注意,也有很多类不是为了多态的用途,例如STL容器和上文的Uncopyable。

条款8、别让异常逃离析构函数

C++中抛出异常时会逐步展开其函数调用栈,清空局部资源,直到异常被catch。

如果析构函数可以抛出异常,那么清空局部资源时局部对象的析构函数再次异常时同时存在两个异常,C++无法处理,可能会过早结束或出现不明确行为。因此,析构函数绝对不要抛出异常,应通过try-catch捕获任何异常。

有时,客户需要处理某些异常,那么类应该提供一个普通成员函数执行相关操作,供用户调用并处理异常。

例如数据库连接这样的类中,假设用户需要处理关闭连接时的异常,同时析构函数不能抛出异常,可以这样:

条款9、绝不在构造和析构过程中调用virtual函数

C++的构造过程是先构造基类再构造子类、先初始化再进入构造函数体;析构过程相反。

对于派生类的构造函数而言,进入其中时基类部分已构造完而派生类部分未构造完,对象类型是基类,故而此时调用虚函数,实际上使用的是基类的虚函数。

析构函数同理。进入析构函数后派生类部分呈未定义值,对象类型是基类,调用的是基类的虚函数。

总而言之,在构造函数与析构函数中虚函数的行为有特殊变化;为了避免出错,不要在其过程中使用虚函数。如果真的有需求,可以改造成非虚函数再使用。

条款10、令operator=返回一个reference to *this

C++中通常支持连锁赋值,采用右结合律:

为了支持这个常规,拷贝运算符需要返回一个引用。这一条款并不强制,但约定俗成。

条款11、在operator=中处理“自我赋值”

考虑这样一个类,其中管理了一个堆对象

总有些时候,会出现实质上“a=a”这种自我赋值的情况。那么这样简单的拷贝运算符就会出错,先释放了自身的pb,又使用了pb:

传统做法是函数开头添加一个测试:

这种做法具备“自我赋值安全性”,但不具备“异常安全性”:例如当new Bitmap异常时,pb指向被删除的内存。

常用的方法有两种,兼顾了“自我赋值安全性”与“异常安全性”:

条款12、复制对象时勿忘其每一个成分

当自己实现拷贝构造/拷贝运算符时,编译器不会警告你遗漏了某些成员变量。因此,必须仔细地复制所有派生类成员,并调用基类的拷贝操作来复制基类成员。

拷贝构造和拷贝运算符中很可能有相当多重复的操作,但因为两个函数性质完全不同,因此不能用其中一个调用另一个来减少冗余。

可以把共同功能放在第三个函数中,并由两个拷贝操作共同调用。

你好,我是飞宇,本硕均于某中流985 CS就读,先后于百度搜索以及字节跳动电商等部门担任Linux C/C++后端研发工程师。

同时,我也是知乎博主@韩飞宇,日常分享C/C++、计算机学习经验、工作体会,欢迎点击此处查看我以前的学习笔记&经验&分享的资源。

有个朋友收集了一些C++开发手册、LeetCode刷题模板等精品资料,可加他的微信免费领取。

标签:

最新
  • 《EffectiveC++》读书笔记(2):构造/析构/赋值运算|每日快报

    点击上方“C语言与CPP编程”,选择“关注 置顶 星标公众号”干货福利,

  • *ST西钢:新增逾期债务本金或净额约2.38亿元-快看

    *ST西钢公告,公司新增逾期债务本金或净额约2 38亿元,占公司最近一期

  • 木桶效应给个人的启示 木桶效应

    1、一只水桶盛水的多少,并不取决于桶壁上最高的那块木块,而恰恰取决

  • 环球热资讯!国防部介绍中国海军参加“科莫多-2023”多国海上联合演习情况

    6月16日下午,国防部新闻局副局长、国防部新闻发言人张晓刚大校就近期

  • 1980年,王守信被执行死刑后的照片,趴在地上已没了生命的体征

    阅读文章前辛苦您点下“关注”,方便讨论和分享,为了回馈您的支持,我

  • 广西职业技术学院与厦门思明区人社局召开校企合作研讨会

    6月15日,厦门市思明区人力资源和社会保障局就业中心主任吴晓欢一行来

  • 央行加量逆回购呵护市场流动性

    受税期影响,资金面有边际转紧的趋势。截至6月16日收盘,DR001上行49 9

  • 五部门:引导金融机构加大对乡村振兴重点领域信贷支持力度

    6月16日,中国人民银行、金融监管总局、中国证监会、财政部、农业农村

  • 强观察|这些返回舱里的“神器”为航天员保驾护航|环球简讯

    6月4日,神舟十五号载人飞船返回舱在东风着陆场成功着陆。记者任军川摄

  • 全球热点!汝州:党建赋能走出富民强村“新路径”

    大河网讯6月15日上午,34岁的汝州市米庙镇石槽王村支部书记张曼曼,正

  • 国防部:中俄联合空中战略巡航有效检验提升两国空军协作水平_焦点速讯

    6月16日下午,国防部新闻局副局长、国防部新闻发言人张晓刚大校就近期

  • 三亚这项资金开始申报! 环球百事通

    关于开展2023年度三亚市文化产业发展专项资金申报的通知各有关单位:根

  • 海南2023养老金调整时间会提前吗 企退养老金补发何时到手?

    有消息吗?海南2023养老金调整及补发时间会提前吗?23年海南养老金调整

  • 美高梅中国(02282)6月16日耗资约1204.07万港元回购125.32万股

    美高梅中国(02282)公布,2023年6月16日耗资约1204 07万港元回购1

  • 【环球新要闻】2023藁城区汽车消费券在哪领?

    2023藁城区汽车消费券需要前往指定的汽车销售公司领取,参与促销企业为

  • 牙的笔顺_齿的笔顺

    你们好,最近小品发现有诸多的小伙伴们对于牙的笔顺,齿的笔顺这个问题

  • 旅游
    • 预期收益和风险之间的关系是什么?预期收益是否能作为损失的依据? 环球最资讯

    • 最新快讯!信用卡逾期会被银行起诉吗?信用卡逾期了怎么协商还款?

    • 全球即时看!仙佑集团膏药供应链管理与企业运营 建设文化特色及其传承

    • 天天速递!理财现金分红是什么意思?股票现金分红怎么扣税?