《Effective C++》学习笔记(条款15:在资源管理类中提供对原始资源的访问)

2021/11/10 1:09:57

本文主要是介绍《Effective C++》学习笔记(条款15:在资源管理类中提供对原始资源的访问),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

最近开始看《Effective C++》,为了方便以后回顾,特意做了笔记。若本人对书中的知识点理解有误的话,望请指正!!!

在资源管理类中存储了我们的原始资源,保证了我们的原始资源必定会执行某些操作,但是有时我们需要用到我们的原始资源,所以资源管理类需要提供对原始资源的访问。如条款13中的投资的例子,我们现在需增加一个获得投资天数的接口

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

shared_ptr<Investment> pInv(createInvestment()); 	//某个Investment的智能指针对象
int days = daysHeld(pInv);							//把智能指针作为参数传入,这是错误的

编译器会在第4行报错,因为传入参数类型不匹配,daysHeld() 需要的是 Investment* 类型,所以这时我们需要从智能指针中访问到原始资源 Investment*。有两个方法可以达到这个目的:显示转换隐式转换

shared_ptr 访问原始资源:

  • 显示转换:它提供了一个函数接口 get() 返回智能指针内的原始指针(的复件)。
  • 隐式转换:它重载了指针取值操作符(-> 、*)允许隐式转换至底部原始指针
int days = daysHeld(pInv.get());//显示转换

class Investment{
public:
    boos isTaxFree() const;
  ...
};

//隐式转换
bool taxable1 = !(pInv->isTaxFree());	//使用->操作符
bool taxable2 = !((*pInv).isTaxFree());	//使用*操作符

因此,我们自定义的资源管理类有时也需要提供一个访问原始资源的途径。如C API提供的字体 FontHandle 分配和释放,我们定义一个可以访问原始资源的资源管理类 Font

FontHandle getFont(); //C API定义的分配字体函数
void releaseFont(FontHandle fh);  //C API定义的释放字体函数

class Font{
public:
    explicit Font(FontHandle fh):f(fh) { 
    	//C只能使用值传递
        //构造时获取资源
    } 
    ~Font() {
        releaseFont(f);//析构时释放资源
    }
    //显式转换函数
    FontHandle get() const {
        return f;
    }
    //隐式转换函数
    operator FontHandle() const {
        return f;
    }
    ...
private:
    FontHandle f;
};

void changeFontSize(FontHandle f, int newSize); //改变字体大小的C API

int main()
{
    Font f(getFont());
    int newFontSize;
    ...
    changeFontSize(f.get(), newFontSize);  		//需要使用get()来显式转换
    changeFontSize(f, newFontSize);  			//隐式转换
}

缺点:

  • 显示转换

    • 每次使用都需要调用 get() 函数
    • RAII资源管理类的目的就是为了防止资源(字体)泄漏,而显然的提供显示转换,增加了泄漏字体的可能性(这时可考虑隐式转换
  • 隐式转换

    • 会增加错误发生的机会

      Font f1(getFont());
      ...
      //原本是想拷贝一个Font对象f2,但不小心把Font写成FontHandle了
      //这会将f1隐式转换为其底部的FontHandle,然后对它拷贝一份副本返回
      //编译器不会对此发出报错的信息,但是当f1被销毁,字体被释放,就会导致f2的字体被损坏。
      FontHandle f2 = f1;
      

到底使用显示转换还是印是转换,取决于自己设计的资源管理类的需求。通常显式转换get() 函数可能是更好的选择,但如果想要代码自然易懂,隐式转换可能更好,两者各有优缺点。

Note:

  • API 往往要求访问原始资源,所以每一个RAII class 应该提供一个”取得其管理的资源“的方法
  • 对原始资源的访问可能经由显示转换或隐式转换。一般而言显示转换比较安全,但隐式转换对用户比较方便

条款16:成对使用new和delete时采取相同形式



这篇关于《Effective C++》学习笔记(条款15:在资源管理类中提供对原始资源的访问)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程