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

资源管理类避免直接处理资源,但是许多APIs直接涉及资源,所以应该提供返回原始资源的函数。

tr1::shared_ptr和auto_ptr都提供一个get成员函数,用来执行显式转换,返回智能指针内部的原始指针(的复件)。

std::tr1::shared_ptr<Investment> pInv(createInvestment());

int daysHeld(const Investment* pi);  //返回投资的天数

int days = daysHeld(pInv);   //错误;需要的是Investment而传的是std::tr1::shared_ptr<Investment>对象。

int days = daysHeld(pInv.get()) //将pInv中的原始指针传给daysHeld

几乎所有智能指针都重载了指针取值操作符(operator->和operator*)允许隐式转换至底部原始指针:

class Investment {
public:
    bool isTaxFree()const;
};
Investment* createInvestment();
void f()
{
    std::tr1::shared_ptr<Investment> pInv1(createInvestment());
    bool taxable = !(pInv1->isTaxFree());//经由operator->访问资源
    ...
    std::tr1::shared_ptr<Investment> pInv2(pInv1);
    bool taxable2 = !((*pInv2).isTaxFree());//经由operator*访问资源
    ...
}

FontHandle getFont(); //C API。为简化,暂略参数
void releaseFont(FontHandle fh);
class Font
{
public:
    explicit Font(FontHandle fh)
        : f(fh)
    {

    }
    FontHandle get()const{return f;} //显式转换函数
    {
        return f;
    }
    ~Font(){releaseFont(f);}
protected:
private:
    FontHandle f;
};
void changeFontSize(FontHandle f, int newSize);
Font f(getFont());
int newFontSize;
...
changeFontSize(f.get(), newFontSize);

某些程序员认为这样到处处理显式转换,让人倒尽胃口,另一个办法是令Font提供隐式转换函数,转型为FontHandle:

class Font
{
public:
    explicit Font(FontHandle fh)
        : f(fh)
    {

    }
    operator FontHandle() const //隐式转换函数
    {
       return f;
    }
    ~Font(){releaseFont(f);}
protected:
private:
    FontHandle f;
};

这样客户调用c api时比较轻松自然:

void changeFontSize(FontHandle f, int newSize);
Font f(getFont());
int newFontSize;
...
changeFontSize(f/*.get()*/, newFontSize); //将Font隐式转换为FontHandle

但是,这个隐式转换会增加错误发生机会,例如客户会在需要Font时意外创建一个FontHandle:

Font f1(getFont());

FontHandle f2 = f1; //本意是拷贝一个Font对象管理资源

                               //却将f1隐式转换成其底部的FontHandle然后复制它。

以上FontHandle由Font对象f1管理, 但那个FontHandle也可通过直接使用f2取得。那几乎不会有好下场,例如当f1被销毁,字体被释放,而f2因此而成为“虚吊的”(dangle)。

RAII class内返回原始资源的函数,确实与“封装”发生矛盾,但RAII class 并不是为了封装某物而存在;他们存在是为了确保一个特殊行为--资源释放--会发生。

posted @ 2012-01-14 22:49  lidan  阅读(285)  评论(0编辑  收藏  举报