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.
原文地址:https://www.cnblogs.com/zoneofmine/p/15220432.html