了解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. java创建图片的缩略图

    //java创建图片的缩略图private void createThumbnail(String filename, int thumbWidth, int thumbHeight, int qua ...

  2. Arthas协助排查线上skywalking不可用问题

    前言 首先描述下问题的背景,博主有个习惯,每天上下班的时候看下skywalking的trace页面的error情况.但是某天突然发现生产环境skywalking页面没有任何数据了,页面也没有显示任何的 ...

  3. 35 _ 队列1 _ 什么是队列.swf

    队列是一种可以实现一个先进先出的存储结构 什么是队列? 队列(Queue)也是一种运算受限的线性表.它只允许在表的一端进行插入,而在另一端进行删除.允许删除的一端称为队头(front),允许插入的一端 ...

  4. disruptor架构二

    小故事:Disruptor说的是生产者和消费者的故事. 有一个数组.生产者往里面扔芝麻.消费者从里面捡芝麻. 但是扔芝麻和捡芝麻也要考虑速度的问题. 1 消费者捡的比扔的快 那么消费者要停下来.生产者 ...

  5. 计算机网络之tcp三次握手

    客户端与服务器之间数据的发送和返回的过程当中需要创建一个叫TCP connection的东西:由于TCP不存在连接的概念,只存在请求和响应,请求和响应都是数据包,它们之间都是经过由TCP创建的一个从客 ...

  6. 入门大数据---Flink开发环境搭建

    一.安装 Scala 插件 Flink 分别提供了基于 Java 语言和 Scala 语言的 API ,如果想要使用 Scala 语言来开发 Flink 程序,可以通过在 IDEA 中安装 Scala ...

  7. Postman之API测试使用全指南

    Postman Postman是一个可扩展的API开发和测试协同平台工具,可以快速集成到CI/CD管道中.旨在简化测试和开发中的API工作流. Postman 工具有 Chrome 扩展和独立客户端, ...

  8. 致Spring Boot初学者

    1.引言 Spring Boot是近两年来火的一塌糊涂,来这里的每一位同学,之前应该大致上学习了web项目开发方面的知识,正在努力成长过程中.因为最近有不少人来向我“请教”,他们大都是一些刚入门的新手 ...

  9. C#客户端通过安全凭证调用webservice

    怎么解决给XML Web services 客户端加上安全凭据,从而实现调用安全的远程web方法?首先,有远程web服务Service继承自System.Web.Services.Protocols. ...

  10. 在java中捕获异常时,使用log4j打印出错误堆栈信息

    当java捕获到异常时,把详细的堆栈信息打印出来有助于我们排查异常原因,并修复相关bug,比如下面两张图,是打印未打印堆栈信息和打印堆栈信息的对比: 那么在使用log4j输出日志时,使用org.apa ...