条款13 以对象管理资源

记住:

★为防止资源泄漏,请使用RAII对象,它们在构造函数中获得资源并在析构函数中释放

★两个常被使用的RAII classes分别是tr1::shared_ptr和auto_ptr。前者通常是较佳选择,∵其copy行为比较直观。若选择auto_ptr,复制动作会使它(被复制物)指向null

------------------------------------------------------------------------

为确保资源总是被释放,应将资源放进对象内,当控制流离开后,该对象的dtor会自动释放那些资源。以对象管理资源的两个关键想法:

  (1)获得资源后立刻放进管理对象;

  (2)管理对象运用dtor确保资源被释放

auto_ptr特殊性质:通过copying函数复制它们,它们会变成NULL,而复制所得的指针将取得资源的唯一拥有权:

    std::auto_ptr<Investment> pInv1( createInvestment() );

    std::auto_ptr<Investment> pInv2( pInv1 );  //现pInv2指向对象,而pInv1为null!!!

可见受auto_ptr管理的资源必须绝对没有一个以上的auto_ptr同时指向它。

auto_ptr的一个替代方案是“引用计数型智能指针”,如tr1::shared_ptr。即该智能指针持续追踪共有多少个对象指向某笔资源,并在无人指向它时自动删除该资源。∴其copying行为正常很多:

    std::tr1::shared_ptr<Investment> pInv2( pInv1 ); //pInv1和pInv2指向同一个对象

auto_ptr和shared_ptr两者都在其destructor内做delete而不是delete[]。这意味着在动态分配而得的array身上使用以上两者十分不好。尽管如此,其仍然能通过编译:

    std::auto_ptr<std::string> aps( new std::string[10] );

条款14 在资源管理类(自己建立的)中小心copying行为

记住:

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

★普遍而常见的RAII class copying行为是:抑制copying、引用计数法。不过其他行为也都可能被实现

--------------------------------------------------------------------------------

举例:

  为确保不忘记将一个被锁住的Mutex解锁,可建立一个class来管理机锁。这样的class基本结构由RAII守则支配:资源在构造期间获得,在析构期间释放

 class Lock {
public:
explicit Lock( Mutex *pm ) : mutexPtr( pm ) {
lock( mutexPtr ); //获得资源
} ~Lock() {
unlock( mutexPtr ); //释放资源
}
private:
Mutex *mutexPtr; //raw资源
};

客户使用时:

 Mutex m;
...
{ //建立一个区块来定义critical section
Lock ml( &m ); //锁定互斥器
... //执行critical section内的操作
} //区块最末尾自动解除互斥器锁定

但若Lock对象被复制,会发生何事???

当一个RAII对象被复制,会有两种处理方式:

方式一:禁止复制

将copying操作声明为private,所以对Lock而言看起来如下:

    class Lock : private Uncopyable {

    ...

    };

方式二:对底层资源祭出“引用计数法”

希望保有资源直到它的最后一个使用者(某对象)被销毁。复制RAII对象时应将该资源的被引用数递增。tr1::shared_ptr便是如此。

对方法二,通常RAII类中只要内含一个tr1::shared_ptr即可实现reference-counting copying行为。而此处要定制tr1::shared_ptr的“删除器”,当引用次数为0时调用(∵tr1::shared_ptr的默认行为是当引用次数为0时删除其所指物):

 class Lock {
public:
explicit Lock( Mutex *pm ) : mutexPtr( pm, unlock ) { lock( mutexPtr.get() ); //get函数返回sp内部raw指针(的复件)
} private:
std::tr1::shared_ptr<Mutex> mutexPtr; //用智能指针替换raw pointer
};

此处无需dtor!因为编译器生成的dtor会自动调用其non-static成员(本例的mutexPtr)的dtor,而mutexPtr的dtor会在互斥器的引用次数为0时自动调用tr1::shared_ptr的删除器(本例为unlock)。

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

记住:

★APIs往往要求访问原始资源,∴每个RAII class应提供一“取得其所管理之资源”的办法

★对原始资源的访问可能经由显式转换或隐式转换。一般而言显式转换较安全,但隐式转换对客户较方便。

---------------------------------------------------------------------------------

有两方法可以将RAII class对象转换为其所内含之原始资源:显式隐式转换

举例:

 class Font {

     public:
explicit Font( FontHandle fh ):f( fh ) {} //获得资源
~Font() { releaseFont(f); } //释放资源
private:
FontHandle f; //原始字体资源
};

假设有大量与字体相关的C API处理的是FontHandles,那么就需将Font对象转换为FontHandle。Font class有两种做法:

方法一:提供显式转换函数:

 class Font {

     public:
...
FontHandle get() const { return f; } //显式转换函数
...
};

客户使用时:

 void changeFontSize( FontHandle f, int newSize ); //C API,需要原始资源
Font f( getFont() ); //获取字体资源,Font是资源管理类
int newFontSize;
...
changeFontSize( f.get(), newFontSize ); //明白地将Font转换为FontHandle

方法二:提供隐式转换函数:

 class Font {

     public:
...
operator FontHandle() const { return f; } //隐式转换函数
...
};

客户使用时:

changeFontSize( f, newFontSize ); //会将Font隐式转换为FontHandle

注:

tr1::shared_ptr和auto_ptr都提供一个get成员函数,用来执行显式转换,其会返回智能指针内部的原始指针(的复件)。而且tr1::shared_ptr和auto_ptr也重载了指针取值操作符(operator->和operator*),它们允许隐式转换至底部原始指针:

std::tr1::shared_ptr<Investment> pi1( createInvestment() );  //令tr1::shared_ptr管理一笔资源

bool taxlabel = !( pi1->isTaxFree() );   //经由operator->访问资源

                      //或bool taxlabel  = !( (*pi1).isTaxFree() ); //经由operator*访问资源

补充:

RAII class内的那个返回原始资源的函数,确实是与“封装”思想矛盾。但RAII并非为了封装某物而存在,所以也没关系。就像很多设计良好的classes一样,它隐藏了客户不需要看的部分,但备妥客户需要的所有东西。

最新文章

  1. DDD 主题交流会总结及计划
  2. 创建面注记PolygonElement
  3. day9-paramiko
  4. 夺命雷公狗ThinkPHP项目之----企业网站11之栏目的删除完成
  5. RAC 环境下参数文件(spfile)管理
  6. sql 添加用户
  7. 解决 Error:No suitable device found: no device found for connection &amp;quot;System eth0&amp;quot;
  8. java排序算法之冒泡排序
  9. JAVA面向对象的三大特性 封装
  10. Linux kernel的中断子系统之(五):驱动申请中断API
  11. 生产者与消费者+Queue(线程安全)
  12. 微信小程序github源码
  13. 前端框架VUE----表单输入绑定
  14. Mesh.CombineMeshes
  15. vue2.0 移动端,下拉刷新,上拉加载更多 插件
  16. HDU 6153 扩展kmp
  17. UI Automation的两个成熟的框架(QTP 和Selenium)
  18. 关于RPG游戏结构撰写的相关探索上篇
  19. c# 日期函数[string.Format----GetDateTimeFormats]格式
  20. Oracle 存储过程了解

热门文章

  1. IOS开发之——获取屏幕的尺寸及各模拟器代表的型号
  2. C#中byte[] 与指针
  3. WCF学习心得
  4. 百度地图SDk 使用
  5. T-sql编程
  6. jQuery ZeroClipboard中Flash定位不准确的解决方案
  7. c# 委托内部构造
  8. 解决Qt4.8.6+VS2010运行程序提示 FTH: (6512): *** Fault tolerant heap shim applied to current process. This is usually due to previous crashes
  9. zoj1025 Wooden Sticks
  10. model、dao、 service 和Comtroll层的关系