• Effective C++ 笔记 —— Item 15: Provide access to raw resources in resourcemanaging classes.


    ,Item 13 introduces the idea of using smart pointers like auto_ptr or tr1::shared_ptr to hold the result of a call to a factory function like createInvestment:

    std::tr1::shared_ptr<Investment> pInv(createInvestment()); // from Item 13

    Suppose that a function you’d like to use when working with Investment objects is this:

    int daysHeld(const Investment *pi); // return number of days investment has been held 

    You’d like to call it like this,:

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

    tr1::shared_ptr and auto_ptr both offer a get member function to perform an explicit conversion, i.e., to return (a copy of) the raw pointer inside the smart pointer object:

    int days = daysHeld(pInv.get()); // fine, passes the raw pointer in pInv to daysHeld

    Like virtually all smart pointer classes, tr1::shared_ptr and auto_ptr also overload the pointer dereferencing operators (operator-> and operator*), and this allows implicit conversion to the underlying raw pointers:

    class Investment 
    { // root class for a hierarchy of investment types
    public:
        bool isTaxFree() const;
        //...
    };
    
    Investment* createInvestment(); // factory function have tr1::shared_ptr manage a resource
    std::tr1::shared_ptr<Investment> pi1(createInvestment());
    
    bool taxable1 = !(pi1->isTaxFree()); // access resource via operator-> 
    std::auto_ptr<Investment> pi2(createInvestment()); // have auto_ptr
    
    // manage a resource via operator*
    bool taxable2 = !((*pi2).isTaxFree()); // access resource
    // ...

    Consider this RAII class for fonts that are native to a C API:

    FontHandle getFont(); // from C API — params omitted for simplicity
    
    void releaseFont(FontHandle fh); // from the same C API
    
    class Font 
    { // RAII class
    public:
        explicit Font(FontHandle fh) // acquire resource;
            : f(fh) // use pass-by-value, because the C API does
        {} 
        ~Font() { releaseFont(f); } // release resource
        //... // handle copying (see Item 14)
    private:
        FontHandle f; // the raw font resource
    };

    Assuming there’s a large font-related C API that deals entirely with FontHandles, there will be a frequent need to convert from Font objects to FontHandles. The Font class could offer an explicit conversion function such as get:

    class Font {
    public:
        //...
        FontHandle get() const { return f; } // explicit conversion function
        //...
    };

    Unfortunately, this would require that clients call get every time they want to communicate with the API:

    void changeFontSize(FontHandle f, int newSize); // from the C API
    Font f(getFont());
    int newFontSize;
    //...
    changeFontSize(f.get(), newFontSize); // explicitly convert Font to FontHandle

    Some programmers might find the need to explicitly request such conversions off-putting enough to avoid using the class. That, in turn, would increase the chances of leaking fonts, the very thing the Font class is designed to prevent. The alternative is to have Font offer an implicit conversion function to its FontHandle:

    class Font 
    {
    public: //... operator FontHandle() const // implicit conversion function { return f; } //... };

    That makes calling into the C API easy and natural:

    Font f(getFont());
    int newFontSize;
    //...
    changeFontSize(f, newFontSize); // implicitly convert Font to FontHandle

    The downside is that implicit conversions increase the chance of errors. For example, a client might accidently create a FontHandle when a Font was intended:

    Font f1(getFont());
    //...
    FontHandle f2 = f1; // oops! meant to copy a Font object, but instead implicitly converted f1 into its underlying FontHandle, then copied that

    Now the program has a FontHandle being managed by the Font object f1, but the FontHandle is also available for direct use as f2. That’s almost never good. For example, when f1 is destroyed, the font will be released, and f2 will dangle.

    Things to Remember:

    • APIs often require access to raw resources, so each RAII class should offer a way to get at the resource it manages.
    • Access may be via explicit conversion or implicit conversion. In general, explicit conversion is safer, but implicit conversion is more convenient for clients.
  • 相关阅读:
    Windows 8 系列 Block Game 随笔
    Windows 8 系列 仿新浪微博图片放大功能 随笔
    正则总结 随笔
    Windows 8 系列 GirdView 滚动事件获取 随笔
    Windows 8 系列 ApplicationSettings 随笔
    Windows 8 系列 Popup 应用 随笔
    JS 写 个简单的 TreeView
    Windows 8 系列 Toast_Title_Badge 随笔
    Js分页条 摆脱JQuery及JQuery分页插件的束缚
    Windows 8 系列 DataTemplateSelector_IValueConverter 随笔
  • 原文地址:https://www.cnblogs.com/zoneofmine/p/15220432.html
Copyright © 2020-2023  润新知