以对象管理资源

  1. 当我们使用工厂函数(返回指向派生类对象的基类指针)获取指向给定对象的指针时,有时我们需要对分配的资源进行管理,因为如果不及时delete这个指针将会造成资源泄露。
  2. 如果由于某些原因没有执行到delete语句,那么就会造成内存泄漏。因此如果把资源放进对象内,我们便可依赖C++的“析构函数自动调用机制”确保资源被释放。
  3. 以对象管理资源(资源获取便是初始化,RAII)的两个关键点:
    (1)获得资源后立刻放进管理对象
    (2)管理对象运用析构函数确保资源被释放
  4. 智能指针通常是管理原始指针的好选择。

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

  1. 由于编译器可能会为资源管理类生成拷贝控制成员,当一个RAII对象被复制时我们可以根据我们的预期来设置拷贝控制成员:
    (1)禁止复制,因为很多时候允许RAII对象被复制并不合理。如果复制动作对RAII class并不合理,我们就应该禁止之。比如weak_ptr
    (2)对底层资源祭出“引用计数法”。有时候我们希望保有资源,直到最后一个使用者(对象)被销毁,这种情况下复制RAII对象,应该将资源的“被引用数”递增,比如shared_ptr。
    (3)复制底部资源,此时使用RAII class的唯一理由是当我们不需要某个副本时确保它被释放。此时复制资源管理对象,应该同时也复制其所包含的资源。
    (4)转移底部资源的拥有权。希望确保永远只有一个RAII对象指向一个未加工资源,即使RAII对象被复制依然如此。
  2. 复制RAII对象必须一并复制它所管理的资源,所以资源的copying行为决定RAII对象的copying行为。
  3. 普遍而常见的RAII class copying行为是:抑制copying、施行引用计数法。不过其它行为也都可能被实现。

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

  1. 如果我们需要RAII对象中包含的原始资源,我们就需要一个函数可将RAII对象转换为其所内含之原始资源,有两个做法可以达成目标:显式转换和隐式转换。
  2. 显式调用可能会使代码显得冗长而使大家不去使用这个RAII class,隐式转换显得更加自然,但是隐式转换会增加错误发生的机会。
  3. 对原始资源的访问可能经由显式转换或隐式转换,一般而言显式转换比较安全,但隐式转换对客户更加方便。

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

  1. 当我们使用new时,内存被分配出来,接着针对此内存会有一个(或更多)析构函数被调用,当我们使用delete时,先是针对此内存会有一个(或更多)析构函数被调用,然后内存才被释放。delete的关键在于即将被删除的内存之内究竟存有多少对象。
  2. 因此我们使用delete时需要知道即将被删除的那个指针,所指的是单一对象或对象数组,因为单一对象的内存布局一般不同于数组的内存布局。数组的内存布局通常还包括“数组大小”的记录,以便delete知道需要调用多少次析构函数,单一对象的内存则没有这笔记录。
  3. 我们对一个指针调用delete时,唯一能够让delete知道内存中是否存在一个“数组大小记录”的办法就是:使用时加上[]delete就认定指针指向一个数组,否则就认定指向单一对象。
  4. 在使用typedef定义数组类型时特别容易出错,因此为了避免诸如此类的错误,最好不要对数组形式做typedef动作。

以独立语句将new出的对象置入智能指针

  1. 这个条款的前提在于C++中调用函数时函数实参的初始化顺序并不固定,假如在new语句以及调用智能指针构造函数这之中另外的实参发生异常,那么就会造成资源的泄漏
  2. 避免上述问题的办法很简单就是使用分离语句,以独立语句将new对象放入指针指针中,这样编译器就不会在它俩之间加入其余实参的执行了。