【Effection C++】读书笔记 条款29~条款30
【Effective C++】读书笔记 Part5 实现
条款29:为异常安全而努力是值得的
当异常被抛出时,待哟异常安全性的函数会:
- 不泄漏任何资源。
- 不允许数据败坏。
异常安全函数提供以下三个保证之一
- 基本承诺。如果异常被抛出,程序内的任何事物仍然在有效状态下。没有任何对象或数据结构会因此而败坏。所有对象都处于一种内部前后一致的状态,但是程序中哦个对象的现实状态不可预料。
- 强烈保证。如果异常被抛出,程序状态不会被改变。调用这样的函数只有如下两种情况:函数调用成功,就是完全成功,如果函数调用失败,程序会回复到“调用函数之前”的状态。
- 不抛出异常。函数保证绝不抛出异常,因为它们总能够完成它们所承诺的功能。
对于任何函数,都应该尽量保证异常安全,注意下面亮点:
- 不要为了表示某件事情发生而改变对象状态,除非那件事情已经真的发生了。
- copy-swap策略,往往能够帮助我们实现“强烈保证”的异常安全,但是“强烈保证”并非堆所有函数都可实现或具备现实意义,有因为效率和复杂度的关系,“基本承诺”的异常安全就已经够用了。
- 函数提供的的“异常安全保证”通常最高只等于其所调用之各个函数的“异常安全保证”中的最弱者。
条款30:透彻了解inlining的里里外外
1. 基础知识
Inline函数会给我们带来许多的好处,它们看起来像函数,动作函数,比洪好的多,可以调用它们但是又不需要承受函数调用所招致的额外开销。编译器最优化设计通常被设计用来浓缩那些“不含函数调用”的代码,所以当使用inline函数时候,编译器就有能力对它执行语境相关最优化。
inline函数通常是将相应的函数本体直接展开在调用点,而舍弃了函数调用。如果函数本体过大,这就会导致目标代码(object code)增大,造成代码膨胀。但是如果inline函数本体很小,编译器针对“函数本体”所产生的目标代码可能比针对“函数调用”产生的目标代码所产出的目标代码更小,同时也拥有了inline函数所带来的效率。
2. inline函数的inlining
inline关键字可以用来修饰普通函数和类的成员函数。对于inline普通函数通常需要将函数定义及其实现放置在头文件中,因为对于大多数build environment而言,都是在编译过程中进行inlining(inline展开),所以对于一个inline函数或者是inline成员函数,都需要定义在头文件内,从而保证编译器在编译阶段就已经拥有了inline函数的定义。
3. 编译器视情况来选择是否inlining
除此之外,inline函数只是向编译器提出一个申请,编译器可以选择忽略。大多数编译器都会拒绝将太过复杂的函数(如带有循环或者递归)进行inlining,而对于所有虚函数也都会拒绝inlining。
由于对于所有的虚函数而言,显然只有在运行时候才能够确定具体执行的函数本体,但是对于inline函数而言,则是在编译阶段就需要了解到函数的具体定义。显然对于virtual函数,编译器无法将其inlining。
除此之外,inline函数(非成员函数)其作用于一般都是在文件作用域内,因为inline函数如果都能够在调用处展开,编译器也没有必要对此函数创建符号,并且在代码段中存储函数的二进制指令(函数本体)。
但是,有些情况下,虽然编译器能够对函数进行inlining,但是也会生成一个函数本体。
如当我们对一个inline函数进行取地址的时候,这时候就强迫编译器生成一个相应的outlined函数本体。
另外,如果我们通过一个函数指针来调用inline函数,编译器往往不会将其inlining,因此根据调用函数的方式不同,编译器会视情况来决定是否inlining。
inline void f(){……}//假设编译器会inline函数f
void ( *pf)()=f;//指向函数的指针f();//这个调用会被inlined,因为是正常调用pf();//这个调用可能不会被inlined,因为它是通过函数指针达成
4. inline函数与构造和析构函数
构造函数和析构函数往往都不适合作为inline函数。虽然在许多情况下,构造函数的函数体都可能十分小,或者为空。
但是看看C++标准对于对象被构建和销毁时候所保证的的事情:
- 当你使用new的时候,动态创建的对象被构造函数自动初始化 。
- 当你使用delete的时候,对应的析构函数将被调用。
- 当你创建一个对象的时候,其每一个base class及其每一个成员变量都会被自动构造。
- 当你销毁一个对象的时候,反向顺序的析构行为会自动发生。
- 如果有个异常在构造函数内抛出,该对象已经构造好的那一部分会自动析构。
等等。
这就注定了本来可能函数体非常小的构造函数和析构函数,在经过编译器的处理后就会变得非常复杂,显然就不适合将其进行inlining。
5. inline函数与函数升级
对于程序库中如果不存在non-inline函数,那么客户端程序一般只需要重新链接即可,并不需要重新编译。
如果客户端程序动态链接程序库,那么可能就无需做任何改变就可直接使用升级了版本的程序库。
但是如果将程序库设计为inline函数会给我们的客户端程序带来一定的冲击。主要是客户端程序中,将包含我们程序库中的inline函数的展开,因而如果程序库升级了inline函数,那么客户端代码也必须要重新编译。这个过程量就会显著增大。
6. inline函数与调试
最后一点要注意的是,inline函数往往无法和调试器完美配合,因为在代码执行中,inline函数已经被展开,显然你无法在一个已经不存在的函数设置断点。
7. 小结
- 请将大多数inline函数限制在小型,被频繁调用的函数身上。这可使日后的调试过程和二进制升级更容易,也可使潜在的代码膨胀问题最小化,使得程序的速度提升机会最大化。
- 不要只是因为function template出现在头文件中,就将它们声明为inline.
【Effection C++】读书笔记 条款29~条款30相关推荐
- 读书笔记_Effective_C++_条款三十一:将文件间的编译依存关系降至最低(第二部分)...
下面再来看书,去理解书上说的Handler classes就简单多了,我们大概过一下. 假设我们要写一个Person类,如下: 1 class Person 2 { 3 private: 4 stri ...
- 读书笔记_Effective_C++_条款七:为多态基类声明virtual析构函数
严格来说,多态分为编译时多态和运行时多态,编译时多态是函数的重载,而运行时多态则是迟绑定技术,即根据基类指针或引用的实际指向来决定采取何种行动,一般来说,多态特指运行时多态.下面我们来举有关C++多态 ...
- 读书笔记_Effective_C++_条款十九:设计class犹如设计type
这里初看到"class"和"type",感觉他们是说的是同一样东西,但仔细读了一下,两者在文中还是有区别的.class侧重于自定义的类,而type侧重于系统预定 ...
- 读书笔记_Effective_C++_条款二十四: 若所有参数皆需类型转换,请为此采用non-member函数...
class A { private:int a; public:A(int x) :a(x){}A operator*(const A& x){return A(a*x.a);} };int ...
- 读书笔记 effective c++ Item 30 理解内联的里里外外 (大师入场啦)
正文 最近北京房价蹭蹭猛涨,买了房子的人心花怒放,没买的人心惊肉跳,咬牙切齿,楼主作为北漂无房一族,着实又亚历山大了一把,这些天晚上睡觉总是很难入睡,即使入睡,也是浮梦连篇,即使亚历山大,对C++的热 ...
- 【Effection C++】读书笔记 条款28:避免返回handles指向对象内部成分
[Effective C++]读书笔记 Part5 实现 条款28:避免返回handles指向对象内部成分 避免返回handles(包括references,指针,迭代器)指向对象内部.遵守这个条款可 ...
- 【Effection C++】读书笔记 条款27:尽量少做转型动作
[Effective C++]读书笔记 Part5 实现 条款27:尽量少做转型动作 C++中的类型转换语法 类型转换语法主要有三种不同的形式: (T)expression //将expression ...
- 【Effection C++】读书笔记 条款26:尽可能延后变量定义式的出现时间
[Effective C++]读书笔记 Part5 实现 条款26:尽可能延后变量定义式的出现时间 非循环中的变量定义 尽量延后变量定义式的出现时间,主要包括两个方面: 直到必须使用变量的时候才对其进 ...
- 【Effection C++】读书笔记 条款01~条款04
[Effection C++]读书笔记 Part1 让自己习惯C++ 条款01:视C++为一个语言联邦 将C++视为一个由相关语言组成的联邦.在其某个次语言中,各种守则简单易懂,容易记住.但当从一个次 ...
最新文章
- phpmyadmin底部出现提示“The configuration file now needs a secret passphrase (blowfish_secret). ”...
- java 匿名类 实现接口_细谈 Java 匿名内部类 【分别 使用 接口 和 抽象类实现】...
- 30天自制操作系统 pdf_30天自制操作系统:第四天:系统界面绘制
- aws ec2 跨帐号共享_AWS共享资源的警告
- java l1 034 点赞_L1-034. 点赞 - osc_msmij2gf的个人空间 - OSCHINA - 中文开源技术交流社区...
- 集成学习—决策树(CART)
- android 获取全局context,说说 Android 中如何在全局获取 Context
- Element Form表单布局(一行多列)
- 一种在BIOS中嵌入应用程序的方法及实现
- 银行核心业务系统性能测试
- 怎么使用openssl来生成一个自签名的x509证书?
- 解决django admin表的外键关联数据过多响应时间过长问题
- 自然语言处理中的迁移学习(上)
- Scala中TypeTags和Manifests的用法
- Pandas-数字前面补0
- 货郎问题和计算复杂度
- Qt QString().sprintf(“%x“)解决打印无符号十六位数
- 你不知道的margin:auto居中原理
- ubuntu14.04安装搜狗输入法
- 齐治堡垒机后台存在命令执行漏洞(CNVD-2019-17294)分析