首页 > 代码库 > exceptional c++简要笔记

exceptional c++简要笔记

1、使用iterators:注意iterator是否失效
2、编写一个不区分大小写的字符串类型,其他方面同string
方案:修改char_traits<char>
3、临时对象
使用const&而不是传值拷贝;
使用前++,避免后++操作;
时刻注意因为参数转换操作而产生的隐藏的临时对象。一个避免它的好办法就是尽可能显式的使用构造函
数。
启用“返回值优化”。
请遵循所谓的“单入口/单出口”规则。绝不要在一个函数里面写有多个return语句。
绝对不要返回局部对象的引用。
4、请使用标准库:

5、异常处理的安全性

6、代码的复杂性
异常完全保证级别:基本保证(保证可销毁性且没有泄露);强烈保证(除了基本保证外,还保证完全的“
要么执行要么不执行”的原子规则)。

要对强异常安全性提供保证,经常(但并不总是)需要你以放弃一部分性能为代码。
如果一个函数含有多重的副作用,那么其总是无法成为强异常安全的。此时,唯一的方法就是将函数分为
几个函数,以使得每一个分出来的函数之副作用能被自动完成。

7、class技术
对于标准程序库中存在的,尽量使用标准程序库,不要老想着自己撰写。
小心隐式转换所带来的隐式临时对象,避免的方法是:让单参数构造成为explicit,且避免写出类型转换
函数。
尽量以const&而不是值传递来传参。 尽量写“a op=b;"而不要写成"a = a op b;"(op代表任何操作符
)。这样不仅比较清楚且通常也比较有效率。

如果你提供了某个运算操作符的标准版(例如operator+),请同时为它提供一份assignment版(例如
operator+=)并且以后者为基础来实现前者。同时也请总是保存op和op=之间的自然关系。

使用以下准则来决定一个运算操作符应该是member function或应该是个nonmember function:
一元运算操作符应该是members;
= () [] 和->必须是members;
assignment版的运算操作符(+= -= /= *=等)都必须是members;
其他所有二元运算操作符都应该是nonmembers。

总是在operator<<和operator>>函数中传回stream references。operator<<不应该成为一个member
function。但通常以一个member function为实作基础(往往是virtual),常取名为print()。

为了一致性,请总是以前++为本,实作出后++。

8、改写虚拟函数
让基类的析构函数成为virtual(除非你确定不会有人企图透过一个pointer-to-base去删除一个derived
object)。
重载:同一个区域内提供同名不同参数类型的函数
覆盖:在子类中改写从父类继承的虚拟函数,名称相同,参数也相同。
隐藏:内层scope的函数会使外层scope的同名函数不可见。
当你要提供一个函数,其名称与继承而来的函数同名时,如果你不想因此遮掩了继承而来的函数,请以
using declaration来突围。
不要在改写虚拟函数的过程中改变默认参数。

9、classes之间的关系
当我们希望塑模出“is implemented in terms of”的关系,请选择membership/aggregation 而不要使
用继承。只有在绝对必要的情况下才使用private 继承,也就是说当你需要存取protected members或是需
要改写虚拟函数时。绝对不要只为了重复运用代码而使用public继承。

尽量避免使用public虚拟函数;最好以template method pattern取代之。
了解什么是design patterns,并运用之。
为了广泛应用classes,最好使用“编译器防火墙”手法来遮掩实作细节。使用一个不透明指标(此指标指
向一个已宣告而未定义的class),将之宣告为“struct XxxxxImpl * pimpl_;",用来存放private members(
包括state variables和member functions)。例如“class Map{private:struct MapImpl * pimpl_;};"。

10、使用或滥用继承:
尽量采用aggregation(包含)来取代继承。当我们准备模塑is-implemented-in-terms-of关系时,尽量
采用包含而不用继承。
当我们需要改写虚拟函数时,需要使用继承。
当我们需要处理protected member--一般说来是指成员函数,因为你绝不会写一个class并令它拥有
public或protected member 变量。
当我们需要在一个base subobject之前先建构used object或是一个base subobject之后摧毁used object
。如果如此些微的寿命差异形成程序的重点,则用继承。
当我们从空基类中获得最佳化的实质利益,使用继承。empty base subobject可占用零空间,empty
member object必须占用非零空间。
如果nonpublic inheritance堪用,就绝对不要考虑public inheritance。public inheritance绝不应该
在缺乏is-a关系的情况下被拿来模塑isimplemented-in-terms-of。
当好的containment/membership还堪用时,绝不要使用inheritance。
如果class相互关系可以多种方式来表现,请使用其中最弱的一种关系。

11、编译期的依赖性
封装和隔离;
在声明一个类的时候,应避免暴露出其私有成员;
应该使用一个形如“struct xxxximpl* pimpl_"的不透明指针来存储私有成员(包括状态变量和成员函数
)例如:
class Map{private: struct MapImpl* pimpl_;};

12、编译级防火墙
将全部私有的成员(包括函数)放入Ximpl中。
但对于私有的虚拟函数,不能将其隐藏在pimpl类中。
如果pimpl中的函数要使用其它函数,可能需要一个指向可见对象的“反向指针”。
保护成员绝不应该被放进pimpl中。

13、“Fast Pimpl”技术
14、名称搜索
如果你给函数提供一个class类型的实参,那么在名称搜索时,编译器将认为包含实参类型的命名空间中
的同名函数为可选函数。

15、接口原则
对于一个类x,如果一个函数提到x,且与x同期提供,那么就是x的逻辑组成部分。
成员函数和非成员函数都是一个class的逻辑组成部分。不过成员函数比非成员函数有更强的关联关系。
在接口原则中,对“同期提供”的最有用的解释是“出现在相同的头文件/命名空间中”。

16、内存管理
几个不同的内存区域:常量数据区、栈区、自由存储区、堆区和全局/静态区

17、auto_ptr

18、对象等同问题

19、自动转换

20、对象的生存期
如果需要的话,请编写一个私有函数来使拷贝操作和拷贝赋值共享代码;千万不要利用“使用显式的析构
函数并且后跟一个Placement new的方法来达到‘以拷贝构造操作实现拷贝赋值操作’”这样的目的。
将拷贝赋值操作声明为“T& T::operator=(cosnt T&)”
不要返回Const T&,尽管这样做避免了诸如“(a=b)=c”的用法;这样做意味着:你无法出于移植性的考
虑而将T对象放入标准程序库之容器,因为其需要赋值操作返回一个单纯的T&。

21、变量初始化
建议总是使用“sometype t(u)”的形式,一来是因为只要可以用“sometype t=u”的地方也同样可以用它
;二来是因为它还有其他优点,比如支持多个参数等。

22、正确使用const
在函数内对非内建的类型采用值返回的方法时,最好让函数返回一个const值。

23、类型转换

24、转呼叫函数
传参时,用传const的引用来代替传值
避免函数内联,除非profiler告诉你有这个必要

25、控制流

exceptional c++简要笔记