您的位置:首页 > 编程语言 > C语言/C++

【Effective c++】条款15:在资源管理类中提供对原始资源的访问

2012-08-30 11:15 477 查看
许多API函数直接指涉资源,除非你永远不用这样的API函数,否则只得绕过资源管理对象直接访问原始资源。

例:条款13导入一个观念:使用智能指针如auto_ptr或tr1::shared_ptr保持factory函数如createInvestment的调用结果:

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

假如你希望某个函数处理Investment对象,像这样:

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

你想要这么调用它:

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

却通不过编译,因为dayHelp需要的是Investment*指针,你传给它的却是个类型为tr1::shared_ptr<Investment>的对象。

这时候你需要一个函数将RAII类对象转换为其所内含之原始资源。有两个做法可以达成目的:显式转换和隐式转换。

tr1::shared_ptr和auto_ptr都提供了一个get成员函数,用来显示转换,也就是它会返回智能指针内部的原始指针(的副本)。

int days = dayHelp(pInv.get());//将pInv内的原始指针传给dayHelp

就像所有智能指针一样auto_ptr和tr1::shared_ptr也重载了指针取值操作符(operator->和operator*),它们允许隐式转换至底部原始指针:

class Investment //investment继承体系的跟类
{
public:
bool isTaxFree() const;
};
Investment* createInvestment();//工厂函数
std::tr1::shared_ptr<Investment> pil(createInvestment());
//令tr1::shared_ptr管理一笔资源

bool taxable1 = !(pil->isTaxFree());//经由operator->访问资源
...
std::tr1::shared_ptr<Investment> pi2(createInvestment());
bool taxable2 = !((*pi2).isTaxFree());//经由operator*访问资源
...

由于有时候还是必须取得RAII对象内的原始资源,做法是提供一个隐式转换函数。

考虑下面这个字体的RAII类

FontHandle getFont();//这是个C API。为求简化省略参数
void releaseFont(FontHandle fh);//来自同一组的C API
class Font
{
public:
explicit Font(FontHandle fh) ;  f(fh)//获得资源
{
}
~Font()
{
releaseFont(f);//释放资源
}
private:
FontHandle f; //原始字体资源
};

假设有大量与字体相关的C API,它们处理的是FontHandle,那么“将Font对象转换为FontHandle”会是一种很频繁的需求,Font类可为此提供一个显示转换函数,像get那样:

class Font
{
public:
...
FontHandle get() const
{
return f;//显示转换函数
}
};

不幸的是客户每当使用API函数必须调用get

void changeFontSize(FontHandle f, int newSize);
Font f(getFont());
int newFontSize;
...
changeFontSize(f.get(),newFontSize);//明白地将Font转换为FontHandle


另一个办法是令Font提供隐式转换函数,转换为FontHandle:

class Font
{
public:
...
operator FontHandle() const //隐式转换函数
{
return f;
}
...
};

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

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

Font f1(getFont());
...
FontHandle f2 = f1;//拷贝了一个Font对象,
//却反而将f1隐式转换为其底部的FontHandle
//然后才复制它

以上程序有个FontHandle有Font对象f1管理,但是那个FontHandle也可以通过直接使用f2取得,这样很容易出问题。例如当f1被销毁,字体被释放,而f2因此策划观念为一个“虚吊的”。

是否该提供一个显示转换函数将RAII类转换为其底部资源,还是应该提供隐式转换函数,答案主要取决于RAII类被设计执行的特定工作,以及被使用的情况。最近设计很可能坚持条款18:“让接口容易被正确使用,不易被误用”。

API往往要求访问原始资源,所以每一个RAII类应该提供一个“取得其所管理的资源”的办法。

对原始资源的访问可能经由显示转换或隐式转换,一般而言显示转换比较安全,但隐式转换对客户比较方便。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐