斯是陋室,惟吾德馨

除了技术,还有更多值得关注……

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
    RAII = Resource Acquisition Is Initialisation。资源获得就是初始化?什么意思?如果没听说过,光看字面,肯定是云里雾里了。还是先来看段代码(进段广告?),出自Bjarne Stroustroup。

// use an object to represent a resource ("resource acquisition is initialization")
class File_handle { // belongs in some support library
    FILE* p;
public:
    File_handle(const char* pp, const char* r)
        { p = fopen(pp,r); if (p==0) throw Cannot_open(pp); }
    File_handle(const string& s, const char* r)
        { p = fopen(s.c_str(),r); if (p==0) throw Cannot_open(pp); }
    ~File_handle() { fclose(p); } // destructor
    // copy operations and access functions
};
void f(string s)
{
    File_handle file(s, "r");
    // use file
}

  这段代码是一个用RAII规则的很好的简例。简单说,RAII是一种C++中关于资源生命周期管理的一种编程范式,RAII提倡把资源作为类的一部分,并且在构造函数中分配资源,析构函数中释放资源。看到这里,新手可能会说,我能够确保fopen成功后,在必要时候fclose掉。但,您真的能够100%确保您头脑能在纷繁复杂的代码中或者反复修改中保持100%的清新吗?If yes,恭喜您,您将是该神话的缔造者,被封为KFC(King From Cpper),并被全世界CPPER膜拜。 :) 而用RAII后,您不必老是担心还有什么资源没有被释放而忧心忡忡,封装的资源会在对象脱离代码SCOPE之后自动释放,因为对象脱离SCOPE之后,会先调用析构函数(释放资源),然后从STACK中被CLEAR。您或许还要问,你说的情况,只有静态分配时候有效,很多时候资源可能需要动态分配,如果是动态分配又该怎么办?总要delete掉吧,还是会有可能忘掉呀,并且似乎RAII并没有什么好处带给我呀。恩,的确没错,所以下面我还可以凑一点字数继续讲。
  有时候,资源的分配与回收的配对并不是表面上看起来那么简单和容易。举个简单例子,对以上CLASS代码我们作动态分配:
void f()
{
  File_handle *fhp = new File_handle("file.txt","r");
  // ... use file
  // forget delete fhp, cause memory leak, result maybe uncertain
}
  我们先不提如何解决,再接着看另外一种情况,假设有如下代码:
ClassA *a = new  ClassA();
ClassB *b = new ClassB();
// a,b do something here
delete a;
delete b;
  如果恰好在第2行出错了该怎么办,那a的资源何时释放?也许按耐不住内心激动的您又要问,这里我们可以捕捉异常并进行处理呀,类似于:
ClassA *a = NULL;
ClassB *b = NULL;
try()
{
  a = new ClassA();
  b = new ClassB();
  //do something
  delete a;
  delete b;
}
catch(...)
{
  delete a;      //Even if a wasn't allocated, it can be still delete.
  delete b;
}
  很好,这样写也没错,但我们有更好的方案:
  C++提供的智能指针auto_ptr可以很好解决上述情况。
auto_ptr a(new ClassA);
auto_ptr b(new ClassB);
//a,b do something
  这样是不是更加简洁了呢?
  写到这里,我简单介绍RAII的使命终于完成,当然您充满好奇的您可能还有很多延伸的疑问,例如:RAII和JAVA、.NET提供的GC有什么联系、相比有何区别、有何优劣?如果我的类中还有共享对象应该如何处理?如何编写异常安全的代码?下面的几篇出自高人的文章可以让您继续探索,但小弟我得先睡觉去了 :)

  RAII和垃圾收集(上) 
  http://dev.csdn.net/article/24/24495.shtm

  RAII和垃圾收集(下)
  http://dev.csdn.net/article/24/24496.shtm

  如何编写异常安全的C++代码
  http://www.uml.org.cn/c%2B%2B/200604245.htm

posted on 2006-12-30 00:31  Alex Lee  阅读(576)  评论(0编辑  收藏  举报