高效C++:构造/析构/赋值
了解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++:构造/析构/赋值的更多相关文章
- EffectiveC++ 第2章 构造/析构/赋值运算
我根据自己的理解,对原文的精华部分进行了提炼,并在一些难以理解的地方加上了自己的"可能比较准确"的「翻译」. Chapter 2 构造 / 析构 / 赋值 条款 05:了解C++ ...
- 《Effective C++》第2章 构造/析构/赋值运算(2)-读书笔记
章节回顾: <Effective C++>第1章 让自己习惯C++-读书笔记 <Effective C++>第2章 构造/析构/赋值运算(1)-读书笔记 <Effecti ...
- 《Effective C++》第2章 构造/析构/赋值运算(1)-读书笔记
章节回顾: <Effective C++>第1章 让自己习惯C++-读书笔记 <Effective C++>第2章 构造/析构/赋值运算(1)-读书笔记 <Effecti ...
- Effective C++ —— 构造/析构/赋值运算(二)
条款05 : 了解C++默默编写并调用哪些函数 编译器可以暗自为class创建default构造函数.copy构造函数.copy assignment操作符,以及析构函数. 1. default构造函 ...
- Effective C++笔记:构造/析构/赋值运算
条款05:了解C++默默编写并调用哪些函数 默认构造函数.拷贝构造函数.拷贝赋值函数.析构函数构成了一个类的脊梁,只有良好的处理这些函数的定义才能保证类的设计良好性. 当我们没有人为的定义上面的几个函 ...
- C++构造/析构/赋值函数
在编写C++程序的时候,我们会为特定某一类对象申明类类型,几乎我们申明的每一个class都会有一个或多个构造函数.一个析构函数.一个赋值运算符重载=.以及拷贝构造函数.这些函数控制着类对象的基础操作, ...
- Effective C++ 笔记二 构造/析构/赋值运算
条款05:了解C++默默编写并调用哪些函数 编译器默认声明一个default构造函数.一个copy构造函数.一个copy assignment操作符和一个析构函数.这些函数都是public且inlin ...
- Effective C++ -- 构造析构赋值运算
05.了解C++默默编写并调用哪些函数 编译产生的析构函数时non-virtual,除非这个类的基类析构函数为virtual 成员变量中有引用和const成员时,无法自己主动生成copy assign ...
- Effective C++笔记(二):构造/析构/赋值运算
参考:http://www.cnblogs.com/ronny/p/3740926.html 条款05:了解C++默默编写并调用哪些函数 如果自定义一个空类的话,会自动生成默认构造函数.拷贝构造函数. ...
随机推荐
- 记一次uboot升级过程的两个坑
背景 之前做过一次uboot的升级,当时留下了一些记录,本文摘录其中比较有意思的两个问题. 启动失败问题 问题简述 uboot代码中用到了一个库,考虑到库本身跟uboot版本没什么关系,就直接把旧的库 ...
- git merge整理
========================================================== git bash merge 一.开发分支(dev)上的代码达到上线的标准后,要合 ...
- robot framework使用小结(四)
robot framework可以采用读excel表这种形式实现数据分离,本文没有实现批量读取excel表内容(还不会),后续有必要就学习哈再更新~~~ 新建测试案例baidu05, 右键项目名rob ...
- SQL注入之常用工具sqlmap
通常来说,验证一个页面是否存在注入漏洞比较简单,而要获取数据,扩大权限,则要输入很复杂的SQL语句,有时候我们还会对大量的URL进行测试,这时就需要用到工具来帮助我们进行注入了. 目前流行的注入工具有 ...
- Web安全之验证码绕过
一,验证码绕过(on client) 首先让burpsuite处于抓包状态,打开pikachu的验证码绕过(on client)随意输入账号和密码,验证码先不输入,点击login,会提示验证码错误 然 ...
- LeetCode63. 不同路径 II
这题和62题类似,只不过这里多了障碍物,只需要把有障碍物的格子的方案数设置为0即可,其他格子还是原来的走法. class Solution { public: int uniquePathsWithO ...
- Java中的过滤器
什么是过滤器(Filter)? 过滤器就是一个实现了特殊接口的Java类.实现对请求资源的过滤的功能. 过滤器是Servlet技术中最为实用的技术. 过滤器有啥用? 对目标资源进行过滤. 自动登录,解 ...
- redis 链接数满了
服务器上可以设置timeout参数,这样可以将限制的连接自动释放掉.
- SELinux已经允许,为什么日志显示的仍然是denied?
从日志可以看到,SELinux的Mode已经修改位了permissive = 1,也就是允许模式,但它前面的日志仍然显示的是“denied".本来我还以为是自己哪里没弄好导致的这个问题,但访 ...
- shall 2-13
1.用一句话概括Shell Shell是一个解释器,介于应用程序(用户)和操作系统之间的一个桥梁,负责命令的解释 2.Shell的编程语言编译型语言: 程序在执行之前需要个专门的编译过程,把程序编译成 ...