Effective C++ 笔记 part 3、4

13.以对象管理资源

  1. 资源包括:内存、文件描述符、互斥锁、图形界面中的字型和笔刷、数据库连接、网络sockets 当不再使用资源时,一定要把它归还给系统

以对象管理资源(资源取得时机便是初始化时机RAII :Resource Acquisition Is Initialization):把资源放进对象内,便可依赖c++的析构函数自动调用机制确保资源被释放

    1. 获得资源后理解放进管理对象中
    2. 管理对象运用析构函数确保资源被释放
  1. auto_ptr被销毁时会自动删除它所指之物,所以一定要注意别让多个auto_ptr指针指向同一对象(否则对象会被删除一次以上,行为未定义)

auto_ptr指针:若通过copy构造函数或者copy assignment操作符复制它,它会变成null,而复制所得的指针将取得资源唯一拥有权,STL容器不能用auto_ptr

  1. shared_ptr是一个RSCPs(引用计数型智慧指针,无法打破环状引用,例如两个没使用的对象彼此互指,好像对象还处在被使用状态),shared_ptr的copy行为比较直观

14.在资源管理类中小心copying行为

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

普遍而常见的 RAII class copying行为是:抑制copying、施行引用计数法

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

  1. APIs往往要求访问原始资源,所以没一个RAII  class应该提供一个“取得其所管理之资源”的办法
  2. 对原始资源的访问可能经由显式转换或隐式转换。一般而言显示转换比较安全

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

  1. 使用new:内存被分配出来 –> 针对此内存会有一个(或更多)构造函数被调用

使用delete:针对此内存一个(或更多)析构函数被调用->释放内存

  1. delete xxx; // 认为指针指向单一对象

delete[] xxx;//认为指针指向一个数组

17.以独立语句将newed对象置入智能指针

  1. 以独立语句将newed对象存入智能指针内(先创建对象,将它置入一个智能指针内,然后再把智能指针传给函数调用。)。如果不这样做,一旦异常被抛出(比如在new对象和执行shared_ptr构造函数之间的某一步异常),有可能导致难以察觉的资源泄露。
  2. shared_ptr构造函数需要一个原始指针,该构造函数是个explicit构造函数。

18.让接口容易被使用,不易被误用

  1. 促进正确使用:接口的一致性,与内置类型的行为兼容
  2. 阻止误用:建立新类型,限制类型上的操作,束缚对象值,消除客户的资源管理责任
  3. shared_ptr支持定制型删除器,可防范DLL问题(cross-DLL problem:对象在一个DLL中被创建,在另一个DLL中被销毁),可被用来自动解除互斥锁等

19.设计class犹如设计type

考虑以下问题:

对象创建、销毁、初始化、赋值(考虑初始化和赋值的差别)、值传递(新type的对象如果以值传递,会发生什么)、合法值、继承关系(是否需要配合某个继承图系)、转换(新type与其他type之间是否需要转换及需要什么转换)、一般化、操作符、函数(需要暴露及需要private的)

20. 宁以 pass-by-reference-to-const(高效) 替换 pass-by-value(有拷贝操作)

(前者通常更高效、避免切割问题(slicing problem),但不适用于内置类型、STL迭代器、函数对象)

  1. 切割问题:当一个derived class对象以by value方式传递并被视为一个base class对象,base class的copy构造函数会被调用,而“造成此对象的行为像个derived class对象”的那些特化性质全被切割掉了,仅仅留下一个base class对象
  2. pass-by-reference-to-const不适用于STL及内置类型

21.必须返回对象时,不返回其reference

  1. 栈对象:函数内的对象(local对象)在函数退出前被销毁了,如果返回某个local对象的reference会引发未定义行为。

绝不要返回pointer或reference指向一个local stack对象,或返回reference指向一个heap-allocated对象,货返回pointer或reference指向一个local static对象而有可能同时需要多个这样的对象

22.将成员变量声明为private

  1. 将成员变量声明为private,这可赋予客户访问数据的一致性,可细微划分访问控制、允许约束条件获得保证,并提供class作者以充分的实现弹性
  2. protected并不比public更具封装性

23.宁以non-member、non-friend替换member函数

  1. namespace和class不同,前者可以跨越多个源码文件而后者不可以
  2. 以non-member、non-friend替换member函数,可以增加封装性、包裹弹性和机能扩充性

24.若所有参数皆需类型转换,请为此采用non-member函数

如果需要为某个函数的所有参数(包括this指针所指的那个隐喻参数)进行类型转换,那么这个函数必须是non-member(否则可能会因为找不到参数匹配的函数而调用失败)

25.考虑写出一个不抛出异常的swap函数

  1. 当std::swap对你的类型效率不高时,提供一个swap函数,并确定和这个函数不抛出异常。
  2. 如果你提供一个member swap,也该提供一个non-swap用来调用前者。对于class(而非templates),也要特化swap。
  3. 调用swap时应针对std::swap使用using声明式,然后调用swap并且不带任何“命名空间资格修饰”。
  4. 为“用户特定类型”进行std templates全特化是好的,但千万不要尝试在std内加入某些对std而言全新的东西。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章