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

本文深入探讨了在资源管理中使用智能指针时,如何在显式和隐式转换之间做出选择,以平衡封装与资源释放的需求。通过分析`shared_ptr`和`auto_ptr`的`get`成员函数,以及它们如何用于访问底层资源,本文阐述了如何在代码中优雅地处理资源。同时,文章还讨论了一种将资源访问封装到类中的方法,以及这种方式可能引入的潜在风险,如资源悬挂问题。最后,文章强调了在资源管理类中返回原始资源时,应权衡封装和资源访问的便利性。

资源管理类避免直接处理资源,但是许多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 并不是为了封装某物而存在;他们存在是为了确保一个特殊行为--资源释放--会发生。

转载于:https://www.cnblogs.com/lidan/archive/2012/01/14/2322616.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值