Effective C++资源管理之(在资源管理类中提供对原始资源的访问)
在资源管理类中提供对原始资源的访问
在前面的文章中我们使用到了C++提供的智能指针以及自己封装的资源管理类,这些类中我们将资源封装在class内部。但是在很多情况下我们需要直接使用到这些资源,所以需要提供一些方法直接使用到这些内部资源,例如shared_ptr的get函数等
示例:
创建一个类
class Investment {};
创建一个函数,会返回一个Investment指针对象
Investment* createInvestment();
我们使用shared_ptr类来管理获得得到的Investment动态对象
std::shared_ptr<Investment> pInv(createInvestment());
现在我们有个函数需要直接处理Investment对象
int daysHeld(const Investment* pi);
如下我们这样调用它是错误的,因为我们需要的是Investment指针对象,而不是shared_ptr类型
int days=daysHeld(pInv);
如果我们要在RAII对象中提供对原始资源的访问,那么有两种方式:显示转换和隐式转换
显示转换
以 shared_ptr
的 get
函数为例
- shared_ptr有一个get函数,可以直接得到内部的资源
- 例如,我们修改上面的错误演示案例,使用pInv的get函数将内部的资源传递给daysHeld函数
//get:得到pInv内部的Investment指针
int days=daysHeld(pInv.get());
设计自己的get函数
- 我们可以模仿shared_ptr,在自己的资源管理类中提供一个功能形似get的函数
- 例如在下面的FontHandle资源管理类中,我们提供了一个get函数,用于返回内部的FontHandle资源
FontHandle getFont(); //得到某种字体
void releaseFont(FontHandle fh);//释放字体
void changeFontSize(FontHandle f, int newSize); //改变字体大小
//FontHandle资源管理类
class Font
{
public:
explicit Font(FontHandle fh) :f(fh) {}
~Font() { releaseFont(f); }
FontHandle get()const
{
return f;
}
private:
FontHandle f;
};
所以在下面的API中我们就可以这么调用
Font f(getFont());
int newFontSize;
changeFontSize(f.get(), newFontSize);
隐式转换
我们修改上面的Font类,为其增加一个隐式转换函数
class Font
{
public:
//隐式转换函数
operator FontHandle()const { return f; }
private:
FontHandle f;
}
现在我们不需要调用get函数,直接使用即可(会自动进行转换)
Font f(getFont());
int newFontSize;
//f会自动调用隐式转换函数转换为FontHandle,然后返回类中的FontHandle对象,将其传入参数1
changeFontSize(f, newFontSize);
但是隐式转换会增加错误发生的机会,例如客户可能会在需要Font时意外创建一个FontHandle:
例如下面将f1中的内部资源拷贝给f2,但是如果f1被销毁了,那么f2就称为“虚吊的”(dangle)
Font f1(getFont());
FontHandle f2=f1; //将f1内部的FontHandle对象拷贝给f2
是否该提供一个显示转换函数(例如get()成员函数)将RAII转换为其底部资源,或是应该提供隐式转换,答案主要取决于RAII被设计执行的特定工作,以及它被使用的情况。“让接口容易被使用,不易被误用”