EC++学习笔记(二) 构造/析构/赋值
条款05:了解c++默默编写并调用了哪些函数
编译器可以暗自为 class 创建default构造函数,copy构造函数,copy assignment操作和析构函数
所有这些函数都是 public 并且 inline
编译器自动生成的析构函数是non-virtual 的
编写一个空类 class Widget{};
相当于:
class Widget{
public:
Widget() {...}
~Widget() {...}
Widget(const Widget& rhs) {...}
Widget& operator=(const Widget& rhs) {...}
};
注意:这些函数仅当被需要(被调用),他们才被编译器创建出来
自动生成的copy构造函数和 copy assignment操作符 只是单纯地将来源对象的每一个non-static 成员变量拷贝到目标对象
三法则:如果一个类需要编写显式析构函数,那么同时需要显式编写copy构造函数和 copy assignment操作符
如果一个类内含 reference成员变量 或内含 const 成员变量时,应该显式编写copy构造函数和 copy assignment操作符
因为 reference变量始终绑定在初始化时的变量之上,不允许更改绑定对象, const 变量也不能因为赋值操作被更改
如果其中声明了一个构造函数,编译器于是不再为它创建default构造函数
条款06:若不想使用编译器自动生成的函数,就该明确拒绝
如果一个类中含有指针变量或文件描述符(两者都是资源对象,内存资源和文件资源,具有 引用语义,即复制操作之后,具有引用语义的对象并没有与原对象分离,而是共同指向同一资源,注意区别于值语义对象)
如果该类具有引用语义,不能使用编译器自动生成的函数(copy构造函数和copy assignment操作符),那么就将这两个函数声明为private并且不予实现
class Widget{
private:
Widget(const Widget& rhs);
Widget& operator=(const Widget& rhs);
};
如果发生Widget对象拷贝的情况,编译器会阻止,如果类内部成员函数调用这两个函数,链接器会报错(因为只有声明却没有定义)
注: boost::noncopyable
可以将下列宏定义置于 class的 private部分
#define DISALOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
TypeName& operator=(const TypeName&)
条款07:为多态基类声明 virtual 析构函数
当derived class 对象经由一个base class 指针被删除,且该base class 带着一个non-virtual 析构函数时,其结果未有定义。
原因:因为是base class 指针,所以指针按照 base class 的析构函数的方式进行解释(即使是该指针指向derived class,但是函数是non-virtual 的,多态不成立)
这样,derived class 内部继承而来的base class 部分被析构掉,而自身原有的部分仍然存在,造成了"局部销毁"
解决方法:给base class 一个 virtual 析构函数(利用多态)
任何 class 只要带有 virtual 函数都几乎确定应该也有一个 virtual 析构函数
所有的标准容器例如 vector,list,string,set,map都不带有 virtual 析构函数 且不作为 base class 使用
所以:禁止继承一个标准容器类或者带有non-virtual 析构函数的 class
条款08:别让异常逃离析构函数
析构函数绝对不要吐出异常(容易造成资源泄露),如果程序遭遇一个"于析构函数期间发生的错误"后无法继续执行,调用abort"强迫结束程序"是个合理选择,这样可以阻止异常从析构函数传播出去
条款09:绝不在构造和析构过程中调用 virtual 函数
derived class 对象内的base class 成分会在 derived class 自身成分被构造之前先构造妥当
对象在derived class 构造函数开始执行前不会成为一个derived class,此时对象会被解析至 base class对象,virtual 函数只会执行base calss对应的那份函数
如果base class 构造函数调用 virtual 函数时,此时 virtual 函数会被编译器解析至base class,而不会下降至derived class
条款10:令 operator= 返回一个reference to *this
这样就可以连续赋值了,比如 a = b = c
class Widget{
public:
Widget& operator=(const Widget& rhs) {
...
return *this;
}
};
这个协议不仅适用于标准赋值形式,也适用于所有赋值相关的运算,例如+=,*=
条款11:在 operator=中处理"自我赋值"
"自我赋值"发生在对象被赋值给自己时
一般而言,如果某段代码操作pointer或reference,而它们被用来"指向多个相同类型的对象",就需要考虑这些对象是否为同一个
class Base{...};
class Derived : public Base{...};
void DoSomething(const Base& rb, Derived* pd); //rb和*pd可能其实是同一对象(基类类型的指针或引用,可以引用基类类型对象,也可以引用派生类类型对象)
如果使用对象来管理资源,资源管理对象在copy发生时有正确的举措,自我赋值是安全的
class Bitmmap{...};
class Widget{
private:
Bitmmap* pb;
};
Widget& Widget::operator=(const Widget& rhs) {
delete pb;
pb = new Bitmmap(*rhs.pb);
return *this;
}
上面赋值操作符中,*this 和 rhs有可能是同一对象,delete pb之后,rhs.pb会发生指向野指针
修改为:
Widget& Widget::operator=(const Widget& rhs) {
if (this == &rhs) return *this;
delete pb;
pb = new Bitmmap(*rhs.pb);
return *this;
}
copy and swap 技术:
pass by reference:
Widget& Widget::operator=(const Widget& rhs) {
Widget tmp(rhs);
swap(rhs);
return *this;
}
pass by value:
Widget& Widget::operator=(Widget rhs) {
swap(rhs);
return *this;
}
条款12:复制对象时勿忘其每一个成分
用户自定义的 copy函数必须复制对象内的每一个成员变量
在为derived class 编写 copy函数时,必须很小心的也复制其 base class 成分,那些成分往往是 private,所以让derived class 的copy函数调用相应的base class 函数的copy函数
Derived::Derived(const Derived& rhs)
: Base(rhs), member(rhs.member) { } Derived& Derived::operator=(const Derived& rhs) {
Base::operator=(rhs);
member = rhs.member;
return *this;
}
copy函数应该确保复制"对象内的所有成员变量"和"所有base class成分"
EC++学习笔记(二) 构造/析构/赋值的更多相关文章
- Effective C++ 笔记二 构造/析构/赋值运算
条款05:了解C++默默编写并调用哪些函数 编译器默认声明一个default构造函数.一个copy构造函数.一个copy assignment操作符和一个析构函数.这些函数都是public且inlin ...
- Effective C++笔记:构造/析构/赋值运算
条款05:了解C++默默编写并调用哪些函数 默认构造函数.拷贝构造函数.拷贝赋值函数.析构函数构成了一个类的脊梁,只有良好的处理这些函数的定义才能保证类的设计良好性. 当我们没有人为的定义上面的几个函 ...
- ES6-个人学习笔记二--解构赋值
第二期,解构赋值如果能够熟练应用确实是个十分方便的功能,但是过分的依赖和嵌套只会让代码理解和维护起来十分困难,是个体现高逼格的表达式呢~ 1,解构赋值的基础 //定义:es6运行按照一定模式,从数组或 ...
- 《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 ...
- WPF的Binding学习笔记(二)
原文: http://www.cnblogs.com/pasoraku/archive/2012/10/25/2738428.htmlWPF的Binding学习笔记(二) 上次学了点点Binding的 ...
- Java IO学习笔记二
Java IO学习笔记二 流的概念 在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些数据保存起来的时候,就要使用输出流完成. 程序中的输入输 ...
- Typescript 学习笔记二:数据类型
中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...
- ES6学习笔记<二>arrow functions 箭头函数、template string、destructuring
接着上一篇的说. arrow functions 箭头函数 => 更便捷的函数声明 document.getElementById("click_1").onclick = ...
随机推荐
- (二)mybaits之ORM模型
前言:为什么还没有进入到mybatis的学习呢?因为mybatis框架的核心思想就是ORM模型,所以好好了解一下ORM模型是有必要哒. ORM模型 ORM(Object Relational Ma ...
- sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) Cannot add a NOT NULL column with default value NULL [SQL: u'ALTER TABLE address_scopes ADD COLUMN ip_version INTEGER NOT NULL']
root@hett-virtual-machine:~# su -s /bin/sh -c "neutron-db-manage --config-file /etc/neutron/neu ...
- Spring MVC能响应HTTP请求的原因?
很多Java面试官喜欢问这个问题: 一个Spring MVC的项目文件里,开发人员没有开发自己的Servlet,只通过注解@RequestMapping定义了方法home能响应发向 /mvc/test ...
- VGG16学习笔记
转载自:http://deanhan.com/2018/07/26/vgg16/ 摘要 本文对图片分类任务中经典的深度学习模型VGG16进行了简要介绍,分析了其结构,并讨论了其优缺点.调用Keras中 ...
- 使用jQuery 发送Ajax
jQuery AJAX 方法 AJAX 是一种与服务器交换数据的技术,可以在不重新载入整个页面的情况下更新网页的一部分. 下面的表格列出了所有的 jQuery AJAX 方法: 构建页面:jqlogi ...
- please upgrade your plan to create a new private reposiory
请升级你的计划来创建一个新的私人仓库 提交仓库到github,要公开,除非买他们服务,所以把勾去掉就好了keep this code private
- js的工厂模式
工厂模式: 什么叫工厂模式,工厂就是大家大脑里想的那样,一个流水线作业的一个东西,只需要满足刚需就可以了,一个人,只干一件事,最后串起来,就是一个事件. 首先需要说一下工厂模式.工厂模式根据抽象程度的 ...
- CF-1082(渣渣只做了前三个)
链接:http://codeforces.com/contest/1082 A. Vasya and Book 题意: n,x,y,d 一本电子书有n页,每一次翻动只能往前或者往后翻d页.求x-> ...
- ECshop二次开发 ECSHOP首页显示积分商城里的商品
以ECSHOP2.7.2官方默认模板为基础 1).首先打开 index.php 文件,在最末尾增加下面函数,注意千万不要写到 “?>” 的外面去,要加在“?>”的前面,加以下代码: /** ...
- (38)zabbix中配置snmp监控
1.首先按照“snmp监控快速配置”文本文档在被监控的主机上安装.配置及启动snmp服务, 具体内容如下: 1).安装snmp yum install net-snmp* -y cp -a /etc/ ...