了解C++默认提供和调用的函数

  • 编译器会自动为每一个空类创建构造函数、拷贝构造函数、赋值运算符以及析构函数

  • 不要使用编译器自动创建的函数,要杜绝这种情况发生,自己编写这些函数

如果不想使用编译器自动生成的函数,要明确拒绝

  • 编译器默认提供的函数,不仅不能给编程带来便利,而且会给在某种情况下引入难以定位的bug,因此应该明确拒绝

  • 拒绝的方式就是明确声明该函数为私有且不提供函数体

    • 私有表示对权限的控制,防止外部在意想不到的情况下调用

    • 不提供函数体,是让编译器在链接的时候报错,明确提示你注意这个函数

class Uncopyable{
private:
Uncopyable(const Uncopyable&);
Uncopyable& operator=(const Uncopyable&);
}
//作为基类继承即可

为多态的基类声明virtual析构函数

  • 如果一个类中有一个虚函数,那么必须将析构函数也申明成虚函数,主要是防止资源泄露(使得析构从下向上依次执行)

  • 如果涉及的类不用于多态,那么就不要声明虚函数,因为虚函数的调用需要借助虚函数列表,调用的效率没有普通函数高

  • 如果不想一个类被实例化,那么就声明该类的虚函数为纯虚函数,且提供其实现

class AbstractClass
{
public:
virtual ~AbstractClass();
} AbstractClass::~AbstractClass()
{
//函数实现
//目的是进行资源释放
}

把异常消灭在析构函数中

  • 析构函数绝对不要吐出异常,这会导致资源部分释放的问题,析构函数中的异常一定要try...catch处理

  • 如果客户需要对某个操作做出反应,且有可能抛出异常,那么就需要提供一个普通函数执行该操作,这样设计的好处:

    • 提供普通函数给客户使用,且明确会抛出异常,使得用户有机会对异常做出合理的处理

    • 析构函数中检查资源释放的状态,做最后的处理

class DBConn
{
private:
DBConnect dbc;
bool closed;
public:
void close()
{
dbc.close();
closed = true;
} ~DBConn()
{
if(!closed)
{
try
{
dbc.close();
} catch(...) {
//停止或记录
}
}
}
}
//解决close会跑出异常的可能

绝不在构造函数和析构函数中调用virtual函数

  • 看清楚描述,是构造函数和析构函数中不能调用虚函数;析构函数本身是可以设计成虚函数的,且在某些情况下,必须设计成虚函数

  • 在构造函数未执行完成之前,类的虚函数表未建立

  • 进入析构函数之前,类的虚函数表已经销毁,无法调用

让operator=返回一个reference to *this

好处:便于连续赋值,类似下面这种执行方式:

a = b = c = d //连续赋值
class Widget
{
public:
Widget& operator+=(const Widget& rhs)
{
return *this;
}
}

在operator=中处理自我赋值

  • 确认任何函数操作一个以上的对象,且对象可能重复,那么需要进行自我赋值的校验

  • 进行自我赋值的判断:地址判断、copy-and-swap

  • copy-and-swap:交换两个对象的数据,在交换的过程中,任意一句语句发生异常,只会导致交换函数本身交换不成功,不会导致程序发生其他异常,程序依然可以运行,状态回到没有调用交换之前,唯一遗憾的就是程序的业务逻辑错了。这种函数我们叫异常安全函数

Widget& operator=(const Widget& rhs)
{
if(this == &rhs)
return *this;
// ...
return *this;
} Widget& operator=(const Widget& rhs)
{
Widget temp(rhs);
swap(temp);
return *this;
} Widget& operator=(Widget rhs) //拷贝发生在参数传入的过程中
{
swap(rhs);
return *this;
}

赋值对象时不要忘记其中的每一个成员

  • 代码静态检查时,有一条规则就是需要初始化每一个成员变量

  • 拷贝构造函数和赋值运算符不能相互调用---记住就好,如果有相同的代码可以提取成一个private函数

  • 拷贝构造的时候一定要拷贝自己的每一个成员,包括基类的每一个成员

高效C++:构造/析构/赋值的更多相关文章

  1. EffectiveC++ 第2章 构造/析构/赋值运算

    我根据自己的理解,对原文的精华部分进行了提炼,并在一些难以理解的地方加上了自己的"可能比较准确"的「翻译」. Chapter 2 构造 / 析构 / 赋值 条款 05:了解C++ ...

  2. 《Effective C++》第2章 构造/析构/赋值运算(2)-读书笔记

    章节回顾: <Effective C++>第1章 让自己习惯C++-读书笔记 <Effective C++>第2章 构造/析构/赋值运算(1)-读书笔记 <Effecti ...

  3. 《Effective C++》第2章 构造/析构/赋值运算(1)-读书笔记

    章节回顾: <Effective C++>第1章 让自己习惯C++-读书笔记 <Effective C++>第2章 构造/析构/赋值运算(1)-读书笔记 <Effecti ...

  4. Effective C++ —— 构造/析构/赋值运算(二)

    条款05 : 了解C++默默编写并调用哪些函数 编译器可以暗自为class创建default构造函数.copy构造函数.copy assignment操作符,以及析构函数. 1. default构造函 ...

  5. Effective C++笔记:构造/析构/赋值运算

    条款05:了解C++默默编写并调用哪些函数 默认构造函数.拷贝构造函数.拷贝赋值函数.析构函数构成了一个类的脊梁,只有良好的处理这些函数的定义才能保证类的设计良好性. 当我们没有人为的定义上面的几个函 ...

  6. C++构造/析构/赋值函数

    在编写C++程序的时候,我们会为特定某一类对象申明类类型,几乎我们申明的每一个class都会有一个或多个构造函数.一个析构函数.一个赋值运算符重载=.以及拷贝构造函数.这些函数控制着类对象的基础操作, ...

  7. Effective C++ 笔记二 构造/析构/赋值运算

    条款05:了解C++默默编写并调用哪些函数 编译器默认声明一个default构造函数.一个copy构造函数.一个copy assignment操作符和一个析构函数.这些函数都是public且inlin ...

  8. Effective C++ -- 构造析构赋值运算

    05.了解C++默默编写并调用哪些函数 编译产生的析构函数时non-virtual,除非这个类的基类析构函数为virtual 成员变量中有引用和const成员时,无法自己主动生成copy assign ...

  9. Effective C++笔记(二):构造/析构/赋值运算

    参考:http://www.cnblogs.com/ronny/p/3740926.html 条款05:了解C++默默编写并调用哪些函数 如果自定义一个空类的话,会自动生成默认构造函数.拷贝构造函数. ...

随机推荐

  1. mysql8.0 解决时区问题

    jdbc:mysql://localhost:3306/databaseName?useUnicode=true&characterEncoding=UTF-8&useOldAlias ...

  2. 01[了解] Dubbo

    什么是Dubbo? 概述 Dubbo是阿里巴巴内部使用的分布式业务框架,2012年由阿里巴巴开源. 由于Dubbo在阿里内部经过广泛的业务验证,在很短时间内,Dubbo就被许多互联网公司所采用,并产生 ...

  3. Python方法函数记录

    目录 python 控制台输出的内容保存到txt 文件 eval函数使用 python 控制台输出的内容保存到txt 文件 import sys class Logger(object): def _ ...

  4. 入门大数据---Redis集群分布式学习

    Redis是什么? 官方介绍: Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库.缓存和消息中间件. 它支持多种类型的数据结构,如 字符串(strings), 散列( ...

  5. Easy [还是概率DP思想……]

    题目描述 某一天\(WJMZBMR\)在打\(osu\)~~~但是他太弱逼了,有些地方完全靠运气\(QaQ\) 我们来简化一下这个游戏的规则 有\(n\)次点击要做,成功了就是\(o\),失败了就是\ ...

  6. 无题II HDU - 2236 【二分图+二分答案】

    题目 这是一个简单的游戏,在一个n*n的矩阵中,找n个数使得这n个数都在不同的行和列里并且要求这n个数中的最大值和最小值的差值最小. Input 输入一个整数T表示T组数据. 对于每组数据第一行输入一 ...

  7. Java基础之Synchronized原理

    思维导图svg: https://note.youdao.com/ynoteshare1/index.html?id=eb05fdceddd07759b8b82c5b9094021a&type ...

  8. 《算法笔记》6.6小节 问题 A: 任务调度

    这道题我一开始看到的时候,想到的是拓补排序,可是这么菜又这么懒的我怎么可能用呢,既然出现在优先队列里面,那么久一定和他有关了 可是并没有使用优先队列 思路: 对于这道题,我们肯定是对他们定义优先级,然 ...

  9. js 图片压缩上传(base64位)以及上传类型分类

    一.input file上传类型 1.指明只需要图片 <input type="file" accept='image/*'> 2.指明需要多张图片 <input ...

  10. Java基础笔记05-06-07-08

    五.今日内容介绍 1.方法基础知识 2.方法高级内容 3.方法案例 01方法的概述 * A: 为什么要有方法 * 提高代码的复用性 * B: 什么是方法 * 完成特定功能的代码块. 02方法的定义格式 ...