注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

天地不仁,以万物为Googol!

天行有常,不以物喜,不以己悲……

 
 
 

日志

 
 

使用auto_ptr管理初始化时的资源  

2008-10-20 21:38:44|  分类: 积累 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
我不记得我以前是否看到过这种惯用法,但我今天在写程序时是自己摸索出来的这种方法,记录如下。

写函数时,有时候会遇到要连续申请一些资源的情况。在顺序申请的过程中,如果有一个失败,需要释放之前所有申请过的资源。而这些资源还需要做一些初始化,有时初始化也会失败导致无法继续以后的功能,需要释放之前的所有资源。大概的C代码如下:
FILE* f=fopen(...);
if (f == NULL)
{
    return;
}

char *buf = malloc(...);
if (buf == NULL)
{
    fclose(f);
    return;
}

if (do_some_init(f, buf) == false )
{
    free(buf);
    fclose(f);
    return;
}
// 初始化成功,正常逻辑


可以看到,初始化失败后的释放工作繁琐且容易错。C++给出的一种惯用法是对每个资源做封装,并利用构造和析构的自动化来自动化释放,比如:
ofstream f(...);
if (!f)
    return;
vector<char> buf(...);
if (buf)
    return;
// 初始化成功,正常逻辑


但在实际使用中,我遇到两个问题:1 有的API是C代码,且没有相应的C++封装(说实话,相应的C++封装不如C API好用)。一方面这类API需要手动调用清理函数,另一方面这些API需要传入C指针做参数。前一个问题需要自己写封装类,后一个问题需要释放出管理资源的句柄(这词tmd谁最先翻译的!);2 每个资源都自己写封装太繁琐。而且封装过程可能会遇到资源所有者转移的问题,仅使用auto_ptr自动管理会遇上多重引用的问题,而自己写一个带引用计数或者使用引用计数又有点杀鸡用牛刀。这两个问题导致很多时候在C++的代码里依旧充斥着C式的判断。

我这回使用的一种初始化方式是,把需要初始化的资源做为一个struct封装,封装里初始化时使用0初始化,析构时只对非0句柄做释放动作。在函数里用auto_ptr先持有待初始化的资源集,并对资源初始化。再所有初始化完成后,如果所有资源都需要继续使用,就调用auto_ptr::release()释放对资源的管理(我实际中就是用这种方法);如果只是一部分要继续使用,则将struct实例中对应资源直接赋0,这样auto_ptr自动析构时就不会释放相应资源了。代码如下:
#include <memory>
struct Resources
{
    FILE *f;
    char *buf;
    Resources() : f(0), buf(0) {}
    ~Resource()
    {
        if (f != 0) fclose(f);
        if (buf != 0) delete [] buf;
    }
}
void func()
{
    std::auto_ptr<Resources> r(new Resources);
    r->f = fopen(...)
    if ( (r->f = fopen(...)) == NULL )
        return;
    if ( (r->buf = new char[..]) == NULL )
        return;
    if (do_some_init(r->f, r->buf) == false )
        return;
    ....
    // 设置或使用完资源
    r.release()
    // 初始化完毕,正常逻辑
}


这种做法并不比C方式节省代码(但是比每个资源做一遍wrap还是省很多的),而且使用了C风格的错误处理(抱歉,我对exception使用并不熟练),优点是将释放工作集中了起来,而且不需要自己去控制哪些释放过,哪些没有释放。代码更简洁清晰,而且func本身可以作为C接口,供其他C API使用。
  评论这张
 
阅读(530)| 评论(6)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017