zoukankan      html  css  js  c++  java
  • 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 并不是为了封装某物而存在;他们存在是为了确保一个特殊行为--资源释放--会发生。

  • 相关阅读:
    Java 中文数字转换为阿拉伯数字
    正则表达式转义符
    git .gitignore详解
    git 陷阱小记
    git log 附加命令归纳
    git 命令归纳版
    《Effective Java》 读书笔记(九)使用try-with-resources 语句替代try-finally
    架构设计 | 接口幂等性原则,防重复提交Token管理
    数据源管理 | OLAP查询引擎,ClickHouse集群化管理
    Java并发编程(04):线程间通信,等待/通知机制
  • 原文地址:https://www.cnblogs.com/lidan/p/2322616.html
Copyright © 2011-2022 走看看