当前位置: 首页 > article >正文

《Effective C++》第三版——构造、析构、赋值运算

  • 《Effective C++》第三版

注意:《Effective C++》不涉及任何 C++11 的内容,因此其中的部分准则可能在 C++11 出现后有更好的实现方式。

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

编译器可以暗自为 class 创建 default 构造函数、copy 构造函数、copy assignment 操作符、析构函数

如果某个类没有声明 copy 构造函数、copy assignment 操作符、析构函数,编译器会声明它们;如果某个类没有声明任何构造函数,编译器会声明默认构造函数。编译器声明的这些函数,只有在被调用的时候才会被创建。

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

为驳回编译器自动提供的技能,可将相应的成员函数声明为 private 并且不予实现。使用像 uncopyable 这样的 base class 也是一种方法

C++11 引入了 =delete,似乎更适合完成这个工作。

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

带有多态性质的 base class 应该声明一个 virtual 析构函数

因为具有多态性质的继承体系中,我们常常使用 base 指针指向 derived 对象,如果此时 base class 的析构函数为 non-virtual 的,则结果未定义

Class 如果不是作为 base class,或者不具备多态性质,就不该声明 virtual 析构函数

拥有 virtual 函数会使得对象必须额外携带某些信息,这些额外开销可能是不必要的。

一般而言,当 class 至少含有一个 virtual 函数时,才将析构函数声明为 virtual。

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

析构函数绝对不要吐出异常。如果一个析构函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下它们或结束程序

考虑下面的情况:

void f(){
	vector<A> va;	// A是一个析构函数可能抛出异常的类
}	// va在这里被销毁

如果 va 中有多个元素在析构过程中均抛出异常,将导致程序终止或者未定义行为

如果某个类的析构函数可能抛出异常,有两种解决方法:

  • 直接调用 std::abort() 结束程序
  • 吞下异常

需要指出的是,这两种做法都不值得推荐,因为它们无法真正地处理异常。

如果客户需要对某个操作函数运行期间的异常做出反应,那么 class 应该提供一个普通函数执行该操作

如果一个析构函数的某个操作,例如调用 close(),可能出现异常,就将这个调用操作移到一个普通函数里,让客户自己去调用。

条款 9:绝对不在构造或析构函数中调用 virtual

在构造和析构期间不要调用 virtual 函数,因为这类调用从不下降至 derived class

在一个多态继承体系中,如果 base 的构造函数中调用了 virtual 函数,在 derived 对象构造 base 对象时,base 构造函数调用的实际上是 base 版本的 virtual 函数,这是因为:derived class 对象在构造 base class 的期间,对象的类型是 bass class 而不是 derived class。

析构函数也同理。

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

因为这样可以支持连续赋值

条款 11:在 operator= 中处理自我赋值

确保当对象自我赋值时 operator= 有良好行为。其中技术包括比较 source 和 target 的地址、静心周到的语句顺序以及 copy-and-swap

这里介绍一下 copy-and-swap 技术:

A& A::operator=(A rhs){		// 注意,这里巧妙地利用值传递实现copy
	swap(rhs);	// *this.swap
	return *this
}

确定任何函数如果操作一个以上对象,而其中多个对象是同一个对象时,其行为仍然正确

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

Copying 函数应该确保复制“对象内的所有成员变量”及“所有 base class”成分

不要尝试以某个 copying 函数实现另一个 copying 函数。应该将共同机能放进第三个函数中,并有两个 copying 函数共同调用


http://www.kler.cn/a/310156.html

相关文章:

  • request爬虫库的小坑
  • ML 系列: 第 24 节 — 离散概率分布(泊松分布)
  • STM32嵌入式闹钟系统设计与实现
  • 解决:WSL2可视化opencv和pyqt冲突:QObject::moveToThread
  • 前端Cypress自动化测试全网详解
  • 论软件维护及其应用子问题
  • 视频美颜SDK与直播美颜工具的实现原理与优化方案
  • JS 常见的排序算法及比较
  • 进程优先级和环境变量
  • 【算法】BFS系列之 FloodFill 算法
  • 算法:TopK问题
  • IMS中的号码规整 5G注册流程中的语音相关参数
  • Java | Leetcode Java题解之第414题第三大的数
  • LEETCODE 每日一题 (单调栈 +滑动窗口模拟)
  • 【H2O2|全栈】关于CSS(6)CSS基础(五)
  • 达梦disql支持上翻历史命令-安装rlwrap
  • 在家找不到手机?除了语音助手,还可以用远程控制!
  • MySQL查询第M条到第N条数据(M<N)
  • Ubuntu20.04点击文件闪退
  • STM32 - 笔记4
  • Github 2024-09-18 C开源项目日报Top10
  • VirtualBox7.1.0 安装 Ubuntu22.04.5 虚拟机
  • 园区网基础组网保姆级(mstp,vrrp,irf,eth-trunk,route-policy,ospf,bgp,rbm,nat,mlag等等)
  • 操作系统之进程
  • 【iOS】引用计数
  • 【AI学习笔记】初学机器学习西瓜书概要记录(二)常用的机器学习方法篇