技术开发 频道

C++箴言:在资源管理类中准备访问裸资源


【IT168技术文档】

  资源管理类真是太棒了。他们是你防御资源泄漏的防波堤,没有这样的泄漏是设计良好的系统的基本特征。在一个完美的世界中,你可以在所有与资源的交互中依赖这样的类,从来不需要因为直接访问裸资源(raw resources)而玷污你的手。但是这个世界并不完美,很多 API 直接涉及资源,所以除非你计划坚决放弃使用这样的 API(这种事很少会成为实际),否则,你就要经常绕过资源管理类而直接处理裸资源(raw resources)。

  例如,以前介绍的使用类似 auto_ptr 或 tr1::shared_ptr 这样的智能指针来持有调用类似 createInvestment 这样的 factory 函数的结果: std::tr1::shared_ptr<Investment> pInv(createInvestment());

  假设你打算使用的一个与 Investment 对象一起工作的函数是这样的:

  int daysHeld(const Investment *pi); // return number of days
  // investment has been held

  你打算像这样调用它,

  int days = daysHeld(pInv); // error!

  但是这代码不能编译:daysHeld 要求一个裸的 Investment* 指针,但是你传给它一个类型为 tr1::shared_ptr<Investment> 的对象。

  你需要一个将 RAII 类(当前情况下是 tr1::shared_ptr)的对象转化为它所包含的裸资源(例如,底层的 Investment*)的方法。有两个常规方法来做这件事。显式转换和隐式转换。

  tr1::shared_ptr 和 auto_ptr 都提供一个 get 成员函数进行显示转换,也就是说,返回一个智能指针对象内部的裸指针(raw pointer)(或它的一个副本):

  int days = daysHeld(pInv.get()); // fine, passes the raw pointer
  // in pInv to daysHeld

  就像实际上的所有智能指针类一样,tr1::shared_ptr 和 auto_ptr 也都重载了指针解引用操作符(pointer dereferencing operators)(operator-> 和 operator*),而这样就允许隐式转换到底层的裸指针(raw pointers):
class Investment { // root class for a hierarchy  public: // of investment types   bool isTaxFree() const;   ... }; Investment* createInvestment(); // factory function std::tr1::shared_ptr<Investment> // have tr1::shared_ptr pi1(createInvestment()); // manage a resource bool taxable1 = !(pi1->isTaxFree()); // access resource // via operator-> ... std::auto_ptr<Investment> pi2(createInvestment()); // have auto_ptr // manage a // resource bool taxable2 = !((*pi2).isTaxFree()); // access resource // via operator* ...
  因为有些时候有必要取得 RAII 对象内部的裸资源,所以一些 RAII 类的设计者就通过提供一个隐式转换函数来给刹车抹油。例如,考虑以下这个 RAII 类,它要为 C++ API 提供原始状态的字体资源:
FontHandle getFont(); // from C API-params omitted // for simplicity void releaseFont(FontHandle fh); // from the same C API class Font { // RAII class  public:   explicit Font(FontHandle fh) // acquire resource;   : f(fh) // use pass-by-value, because the   {} // C API does   ~Font() { releaseFont(f); } // release resource  private:   FontHandle f; // the raw font resource };
  假设有一个巨大的与字体有关的 C++ API 只能与 FontHandle 打交道,这就需要频繁地将 Font 对象转换为 FontHandle。Font 类可以提供一个显式的转换函数,比如 get:
class Font {  public:   ...   FontHandle get() const { return f; } // explicit conversion function   ... };
0
相关文章