Effective C++总结(一)

Effective C++总结

    从8月24到今天刚刚好一个月,期间请假回家考驾照,开学,继续实习,到今天看完了.感觉还是挺有收获的.相比较七月份看的 深度探索C++对象模型,这本书更实际,(那本书感觉比较偏向编译器底层,有点让人无从总结),下面记一下每章节的重点,但是没有代码好不适应.满满地没有读的欲望 哭,但是感觉真的非常实用.

导读

    详见 这里.声明式(declaration)是告诉 编译器某个东西的名称和类型,但忽略细节.定义式是编译器为此对象所分配内存的地点.

第1章   让自己习惯C++

条款01: 视C++为一个语言联邦

    详见 这里.最简单的方法是将C++视为一个由相关语言组成的联邦而非单一语言.C++主要有以下四个次语言:C,Object-Oriented C++,Template C++,STL.

条款02: 尽量以 const,enum,inline 替换 #define

    详见 这里.对于单纯变量,最好以 const 对象或 enums 替换#define.对于形似函数的宏,最好改用 inline 函数替换#define.

条款03: 尽可能使用 const

    详见 这里. const 允许指定一个语义约束(也就是指定一个"不该被改动"的对象),而编译器会强制实施这项约束.它允许告诉编译器和其他程序员其值应该保持不变.只要这(某值保持不变)是事实,因为说出来可以获得编译器的帮助,确保这条约束不被违反.
    const 最具威力的用法是面对函数对象时的应用.在一个函数声明式内,const 可以和函数返回值,各参数,函数本身产生关联.令函数返回一个常量值,往往可以降低因客户错误而造成的意外,而又不至于放弃安全性和高效性.

条款04: 确定对象被使用前已被初始化

    详见 这里.C++规定,对象的成员变量的初始化动作发生在进入构造函数本体之前.使用所谓的member initializaition list(成员初始化列表)替换赋值操作.基于赋值的那个版本首先调用default构造函数为theName,theAddress和thePhones设初值,然后立刻再对它们赋予新值.default构造函数的一切作为都浪费了.对大多数类型而言,比起先调用default构造函数再调用copy assignment操作符,但只调用一次copy构造函数是比较高效的,有时甚至高效得多.
    C++有着十分固定的"成员初始化次序".base classes早于其derived classes被初始化,而 class 的成员变量总是以其声明次序被初始化.
    将每个non-local static 对象搬到自己的专属函数内(该对象在此函数内声明为static).这些函数返回一个reference指向它所含的对象.然后用户调用这些函数,而不直接指涉这些对象.换句话说,non-local static 对象被local static 对象替换了.这就是Singleton模式的一个常见实现手法.
    这个手法的基础在于:C++保证,函数内的local static 对象会在"该函数被调用期间""首次遇上该对象的定义式"时被初始化.

第2章   构造/析构/赋值运算

条款05: 了解C++默默编写并调用哪些函数

    详见 这里.什么时候empty class 不再是个empty class 呢?当C++处理过它之后.如果自己没有声明,编译器就会为它声明一个copy构造函数,一个copy assignment操作符和一个析构函数.此外如果没有声明任何构造函数,编译器也会声明一个default 构造函数.所有这些函数都是 public 且 inline.

条款06: 若不想使用编译器自动生成的函数,就该明确拒绝

    详见 这里.借由明确地声明一个成员函数,可以阻止编译器暗自创建其专属版本;而令这些函数为 private,得以成功阻止其他人调用它.将成员函数声明为private并且故意不实现它们.

条款07: 为多态基类声明 virtual 析构函数

    详见 这里.C++明确指出,当derived class 对象经由一个base class 指针来删除,而该base class 带着一个non-virtual 析构函数,其结果未有定义——实际执行时通常发生的是对象的derived成分没有被销毁.
    消除这个问题的办法很简单:给base class 一个 virtual 析构函数,此后删除derived class 对象就会达到目的.它会销毁整个对象,包括所有derived class 成分.

条款08: 别让异常逃离析构函数

    详见 这里. 析构函数绝对不要吐出异常.如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下它们(不传播)或结束程序.
    如果客户需要对某个操作函数运行期间抛出的异常做出反应,那么 class 应该提供一个普通函数(而非在析构函数中)执行该操作.

条款09: 绝不在构造和析构过程中调用 virtual 函数

    详见 这里.在构造和析构期间不要调用 virtual 函数,因为在derived class 对象的base class 构造期间,对象的类型是base class 而不是derived class.不只是 virtual 函数会被编译器解析至base class.若使用运行期类型信息(如 dynamic_cast 和 typeid)也会把对象视为base class 类型。对象在derived class 构造函数开始执行前不会成为一个derived class 对象.

条款10: 令 operator=返回一个reference to *this

    详见 这里.为了实现"连锁赋值",赋值操作符必须返回一个reference指向操作符的左侧实参.

条款11: 在 operator=中处理"自我赋值"

    详见 这里.自我赋值问题是,operator=函数内的*this(赋值的目的端)和rhs有可能是同一个对象.如果这样的话,delete 就不只是销毁当前对象的bitmap,它也销毁rhs的bitmap.在函数末尾,Widget发现自己持有一个指针指向一个已被删除的对象.
    欲阻止这种错误,传统做法是借由 operator=最前面的一个"证同测试"达到"自我赋值"的检验目的.
    但这个新版本仍然存在异常方面的麻烦.让 operator=具备"异常安全性"往往自动获得"自我赋值安全"的的回报.因此只需要把焦点放在实现"异常安全性"上.

条款12: 复制对象时勿忘其每一个成分

    详见 这里.编写一个copying函数,确保(1)复制所有local成员变量,(2)调用所有base classes内的适当的copying函数.

第3章   资源管理

条款13: 以对象管理资源

    详见 这里.为确保createInvestment返回的资源总是被释放,需要将资源放进对象内,当控制流离开f,该对象的析构函数会自动释放那些资源.实际上这正是隐身于本条款背后的半边想法:把资源放进对象内,便可依赖C++的"析构函数自动调用机制"确保资源被释放.
    auto_ptr是个"类指针对象",也就是所谓"智能指针",其析构函数自动对其所指对象调用 delete.
    "引用计数型智能指针"tr1::shared_ptr,持续追踪共有多少对象指向某笔资源,并在无人指向它时自动删除该资源.

条款14: 在资源管理类中小心copying行为

    详见 这里.复制RAII对象必须一并复制它所管理的资源,所以资源的copying行为决定RAII对象的copying行为.

条款15: 在资源管理类中提供对原始资源的访问

    详见 这里.API往往要求访问原始资源(raw resources),所以每一个RAII class 都应该提供一个"取得其所管理的资源"的办法.

条款16: 成对使用 new 和 delete 时要采取相同形式

    详见 这里.当使用 new(也就是通过 new 动态生成一个对象),有两件事发生.第一,内存被分配出来(通过名为operator new 的函数).第二,针对此内存会有一个(或更多)构造函数被调用.当使用 delete,也有两件事发生:针对此内存会有一个(或更多)析构函数被调用,然后内存才被释放(通过名为operator delete 的函数.delete 的最大问题在于:即将被删除的内存内究竟有多少个对象?这个问题的答案决定了有多少个析构函数必须被调用.
    即将被删除的那个指针,所指的是单一对象还是对象数组?这是个必不可缺的问题,因为单一对象的内存布局一般而言不同于数组的内存布局.更明确地说,数组所用的内存通常还包括"数组大小"的记录,以便 delete 知道需要调用多少次析构函数.单一对象的内存则没有这笔记录.
    办法就是:告诉它.如果使用 delete 时加上中括号,delete 便认定指针指向一个数组,否则它便认定指针指向单一对象:

条款17: 以独立语句将 newed 的对象置入智能指针

    详见 这里. 以独立语句将newed对象存储于(置入)智能指针内.如果不这样做,一旦异常被抛出,有可能 导致难以察觉的资源泄露.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值