[笔记]《Effective C++》第三章 Resource Management

条款13:Use objects to manage resources.

  1. 为防止资源泄漏,请使用RAII对象,它们在构造函数中获得资源并在析构函数中释放资源
  2. 两个常被使用的RAII classes分别是shared_ptrauto_ptr。前者通常是较佳选择,因为其copy行为比较直观。若选择auto_ptr,复制动作会使它(被复制物)指向null。
  3. 注意:在C++11 =中已经摒弃auto_ptr转向使用unique_ptr,后者禁止copy构造赋值
 auto_ptr<int> ap(new int(10));
 auto_ptr<int> aone(ap);
 auto_ptr<int> atwo = aone;
 //这样是没问题的

 unique_ptr<int> up(new int(10));
 unique_ptr<int> uone(up);
 unique_ptr<int> utwo = up;
 //上面两行会编译失败
  • 把资源放进对象内,我们便可倚赖 C++的“析构函数自动调用机制”确保资源被释放。
  • 智能指针,如auto_ptr, shared_ptr, unique_ptr等,其析构函数自动对其所指对象调用delete
  • “以对象管理资源”的两个关键想法:
    • 获得资源后立刻放进管理对象(managing object)内。这就是大名鼎鼎的“资源取得时机便是初始化时机”(Resource Acquisition IsInitialization;RAII)。
    • 管理对象(managing object)运用析构函数确保资源被释放
  • shared_ptr“引用计数型智慧指针”(reference-counting smart pointer;RCSP),RCSP会持续追踪共有多少对象指向某笔资源,并在无人指向它时自动删除该资源

条款14:Think carefully about copying behavior in resource-managing classes.

  1. 复制RAII对象必须一并复制它所管理的资源,所以资源的copying行为决定RAII对象的copying行为
  2. 普遍而常见的RAII class copying行为是:抑制 copying(auto_ptr,unique_ptr)、施行引用计数法(reference counting)(shared_ptr)。不过其他行为也都可能被实现。
  • “当一个 RAII 对象被复制,会发生什么事?”:
    • 禁止复制。条款6告诉你怎么做:将copying操作声明为private。(unique_ptr)
    • 对底层资源祭出“引用计数法”(reference-count)。(shared_ptr)
    • 复制底部资源。复制资源管理对象时,进行的是“深度拷贝”。
    • 转移底部资源的拥有权。资源的拥有权会从被复制物转移到目标物。(auto_ptr)

条款15:Provide access to raw resources in resource-managing classes.

  1. APIs往往要求访问原始资源(raw resources),所以每一个RAII class应该提供一个“取得其所管理之资源”的办法。
  2. 对原始资源的访问可能经由显式转换隐式转换。一般而言显式转换比较安全,但隐式转换对客户比较方便
  • RAII classes并不是为了封装某物而存在;它们的存在是为了确保一个特殊行为——资源释放——会发生。

条款16:Use the same form in corresponding uses of new and delete.

如果你在new表达式中使用[]必须在相应的delete表达式中也使用[]。如果你在new表达式中不使用[]一定不要在相应的delete表达式中使用[]

  • 如果你使用 delete时加上中括号(方括号),delete便认定指针指向一个数组否则它便认定指针指向单一对象

条款17:Store newed objects in smart pointers in standalone statements.

独立语句newed对象存储于(置入)智能指针内。如果不这样做,一旦异常被抛出,有可能导致难以察觉的资源泄漏。

//declarition
int priority();
void processWidget(std::shared_ptr<Widget> pw, int priority);

//错误的调用,可能会导致泄漏资源
processWidget(std::shared_ptr<Widget>(new Widget), priority());

//正确的调用,不会泄露资源
std::shared_ptr<Widget> pw(new Widget);
processWidget(pw, priority());
  • C++编译器在核算函数中被传递的各实参时,顺序不是固定的,在上面的错误调用中,可能会先执行"new Widget",然后在调用shared_ptr之前调用priority,此时若对priority函数调用导致异常,"new Widget"返回的指针尚未被置入shared_ptr,指针遗失,此时发生资源泄露。
  • 编译器对于“跨越语句的各项操作”没有重新排列的自由(只有在语句内它才拥有那个自由度)。
posted @ 2021-09-08 21:16  浮生的刹那  阅读(43)  评论(0)    收藏  举报