effective c++ 笔记 (5-8)
//---------------------------15/03/26----------------------------
//#5 了解c++默默编写并调用哪些函数
{
/*
c++会默默帮你声明一个copy构造函数,一个copy assignment操作符重载,
一个析构函数,一个default构造函数。并且都是 public inline的
因此如果写下:
*/
class Empty{};
//就好像写下这样的代码:
class Empty
{
public:
Empty(){...}
Empty(const Empty& rhs) {...}
~Empty(){...}
Empty&operator=(const Empty& rhs){...}
};
//1:这些函数,只有被需求(被调用)时,才会被编译器创建出来
/**
2:copy构造函数和copy assignment操作符,编译器创建的版本只是单纯地
将来源对象的每一个non_static成员拷贝到目标对象中去
**/
//3:在copy的时候:如果成员变量有copy构造函数,编译器就调用其copy构造函数,
//如果没有copy构造函数,就会拷贝每一个bits
来完成初始化
/*
4:在什么情况下编译器拒绝帮忙定义一个copy assignment?
1>对象内包含一个reference变量,原因:reference自身不可以被再次指向另一个值
如果你想让这个reference的内容改变成目标对象的内容,那需要自行实现operator=操作
其实也就是深拷贝。
2>对象内包含一个const变量,原因:更改const变量的值时不合法的。
3>如果base classes将copy assignment操作符声明为private。原因:原本derived
classes
的copy assignment操作符是可以处理base class成分的,但是现在他们无法调用了。
编译器就两手一摊,无能为力了。
*/
}
//#6 若不想使用编译器自动生成的函数,就该明确拒绝
{
/*
当你想使你的对象不能被复制时(比如每个人的资产都是私有的,不该被复制给别人),
你有两个方法可以做到: */
// 1>自己声明一个private的copy构造函数以及copy assignment操作符。
class HomeForSale
{
public:
...
private:
...
HomeForSale(const HomeForSale&);
HomeForSale&operator=(const HomeForSale&);
};
// 这样就声明了这两个函数,要注意的是,不要去实现它,这样可以在别人
// 使用这两个函数时报错(编译器报错),当成员函数或friend函数使用时,会产生连接时报错
// 2>为了时报错提早(所有报错都由编译器产生),可以专门设计一个base类:
class Uncopyable
{
protected:
Uncopyable(){}
~Uncopyable(){}
private:
Uncopyable(const Uncopyable&);
Uncopyable&operator=(const Uncopyable&);
};
/*
这样只要想阻止copying行为,只需要继承Uncopyable类就可以了
这里会产生几个微妙的实现和运用
1>不一定需要使用public继承
2>Uncopyable的析构函数可以不是virtual的(这个类不是接口,只能算是一个属性)
3>Uncopyable中不含数据,符合一个empty base class optimization的资格
4>由于常常被继承,很可能造成多重继承。
*/
//总结:如果你的类常需要从多个基类继承,那最好自己声明两个copy函数,否则,不妨从
//Uncopyable那继承。
}
//#7 为多态基类声明virtual析构函数
{
/*
这一点,不必多说,只要了解c++多态,都知道要给多态基类声明一个virtual析构函数防治内存泄漏
这个条款中比较新鲜的东西有两个:
1:不要为一个非多态用途的类声明virtual析构函数。原因是:
1>这么做会使的对象占用内存变大,
尤其是对于一些小巧的类来说,本来可以直接放在一个寄存器中的,一声明vitual属性,
在32位系统中就变大了32bits,在64位系统中就变大了64bits。这个大小就是一个指针的大小,
这个指针就是vptr指针,指向虚函数表,里面存放着由函数指针
构成的数组。
2>由于vptr指针,这个对象将变得没有移植性。因为其他语言没有vptr这东西。
2:如果想使一个base class获得不能被实例化
的特性,而这个base calss中又没有
pure vitual函数(纯虚函数),可以把析构函数设置为pure vitual函数。值得注意的是
你还是要为这个析构函数提供一份定义。因为基类析构函数总是会在其派生类调用时被调用。
*/
}
//#8 别让异常逃离析构函数
{
// 如果析构函数可以吐出异常,会造成程序的结束执行或不明确行为,看下面的例子:
class Widget
{
public:
...
~Widget(){...}
};
void doSomething()
{
std::vector<Widget> v;
}
/*
当vector被销毁时,vector会依次调用其中的所有widget对象(假设有10个),如果析构允许
抛出异常的话,析构第一个的时候,抛出了异常,为了确保不会发生内存泄漏,必须继续析构其他
九个widget,如果第二个异常又被抛出,现在有两个同时作用的异常,在两个异常同时存在的情况下,
程序不是结束执行就是导致不明确行为。
*/
//如果析构函数必须执行一个动作,而该动作可能在失败时抛出异常,那么应该这么做
//给客户提供一个动作,让他自己去调用,并在析构函数中检查是否完成,并吞下异常或终止程序
class DBConn
{
public:
...
void close()
{
db.close();
closed =true;
}
~DBConn()
{
if(!closed)
{
try
{
db.close();
}catch (...)
{
//记下对close调用失败的log
//选择是否中止
}
}
}
private:
DBConnection db;
bool closed;
};
//这样可以给客户一个调用close的机会,如果他自己不处理,也没法抱怨设计这个类的我们了。
}
effective c++ 笔记 (5-8)的更多相关文章
- Effective Java笔记一 创建和销毁对象
Effective Java笔记一 创建和销毁对象 第1条 考虑用静态工厂方法代替构造器 第2条 遇到多个构造器参数时要考虑用构建器 第3条 用私有构造器或者枚举类型强化Singleton属性 第4条 ...
- [Effective JavaScript 笔记] 第4条:原始类型优于封闭对象
js有5种原始值类型:布尔值.数字.字符串.null和undefined. 用typeof检测一下: typeof true; //"boolean" typeof 2; //&q ...
- [Effective JavaScript 笔记] 第5条:避免对混合类型使用==运算符
“1.0e0”=={valueOf:function(){return true;}} 是值是多少? 这两个完全不同的值使用==运算符是相等的.为什么呢?请看<[Effective JavaSc ...
- [Effective JavaScript 笔记]第3章:使用函数--个人总结
前言 这一章把平时会用到,但不会深究的知识点,分开细化地讲解了.里面很多内容在高3等基础内容里,也有很多讲到.但由于本身书籍的篇幅较大,很容易忽视对应的小知识点.这章里的许多小提示都很有帮助,特别是在 ...
- [Effective JavaScript 笔记]第27条:使用闭包而不是字符串来封装代码
函数是一种将代码作为数据结构存储的便利方式,代码之后可以被执行.这使得富有表现力的高阶函数抽象如map和forEach成为可能.它也是js异步I/O方法的核心.与此同时,也可以将代码表示为字符串的形式 ...
- [Effective JavaScript 笔记]第28条:不要信赖函数对象的toString方法
js函数有一个非凡的特性,即将其源代码重现为字符串的能力. (function(x){ return x+1 }).toString();//"function (x){ return x+ ...
- java effective 读书笔记
java effective 读书笔记 []创建和销毁对象 静态工厂方法 就是“封装了底层 暴露出一个访问接口 ” 门面模式 多参数时 用构建器,就是用个内部类 再让内部类提供构造好的对象 枚举 si ...
- Effective STL 笔记 -- Item 6 ~ 7: Container and Object Pointer
Effective STL 笔记 – Item 6 ~ 7: Container and Object Pointer 中间两次笔记被删掉了,简单补一下: Item 3 中提到如果将对象直接放入容器中 ...
- Item 5:那些被C++默默地声明和调用的函数 Effective C++笔记
Item 5: Know what functions C++ silently writes and calls 在C++中,编译器会自己主动生成一些你没有显式定义的函数,它们包含:构造函数.析构函 ...
- effective c++ 笔记 (1-3)
// // effective c++.cpp // 笔记 // // Created by fam on 15/3/23. // // //-------------------------- ...
随机推荐
- RHEL7.3安装mysql5.7
RHEL7.3 install mysql5.7 CentOS7默认安装MariaDB而不是MySQL,而且yum服务器上也移除了MySQL相关的软件包.因为MariaDB和MySQL可能会冲突,需先 ...
- RecyclerView使用技巧(item动画及嵌套高度适配解决方案)
原文地址 · Frank-Zhu http://frank-zhu.github.io/android/2015/02/26/android-recyclerview-part-3/?utm_sou ...
- 使用AndroidStudio上传忽略文件至SVN Server的解决措施
在同组项目进行共享时,容易把本地的配置文件比如*.iml等文件上传至共享服务器,这样会对队友造成巨大的麻烦,为了解决这个问题,可以使用下面方法解决,下面以上传到服务器的app.iml文件为例. 一.在 ...
- elasticsearch安装步骤
今天我们来安装一下elasticsearch,我们采用RPM包安装的方式来,版本为6.5.4.系统为centos7.5版本. 1.首先设置系统环境 1)编辑/etc/sysctl.conf文件添加下面 ...
- plsqldev、oracle插入中文乱码问题解决
最近在开发项目时用到Oracle数据库,需要手动插入一些数据,但插入中文的sql值时出现了乱码. 中文乱码就是编码不统一所导致的了,解决办法只需要把编码统一下即可解决了. 此种情况最大的可能就是客户端 ...
- webpack分离css单独打包
这篇文章过期了,webpack4.x已经不这么用了,最新的可以看这个地址webpack实战场景系列 原文地址:http://www.izhongxia.com/posts/44724.html CHA ...
- [AHOI2014/JSOI2014]支线剧情
题目 有源汇上下界最小费用可行流 首先注意到要求是每一条边都经过至少一次,所以对于每一条边我们设成\([1,\infty]\)就好了 另外所有点都能结束剧情,所有点都要向汇点\(t\)连一条\([0, ...
- trycatche
<?phpheader("Content-type: text/html; charset=utf-8"); try{$aaa = 0;if ($aaa == 9) {ech ...
- 使用 rem 作为单位使页面自适应设备宽度
一.新建 rem.js 文件,代码如下: export default function () { document.documentElement.style.fontSize = document ...
- vagrant设置虚拟机的名字
如果我们不在vagrant init 命令生成的vagrantfile文件中声明虚拟机的名字的话,一般会默认给我们指定一个名字,指定的方法: config.vm.provider "virt ...