You can fix that oversight, as illustrated in Chapter 14, “Reusing Code in C++,” but it would be nice if there were a neater solution. Let’s think about what is needed. When a function such as remodel() terminates, either normally or by throwing an exception, local variables are removed from the stack memory—so the memory occupied by the pointer ps is freed. It would be nice if, in addition, the memory pointed to by ps was freed. If ps had a destructor, that destructor could free the pointed-to memory when ps expires. Thus, the problem with ps is that it is just an ordinary pointer and not a class object having a destructor. If it were an object, you could have its destructor delete the pointed-to memory when the object expires. And that is the idea behind auto_ptr, unique_ptr, and shared_ptr. The auto_ptr template is the C++98 solution. C++11 deprecates auto_ptr and provides the other two as alternatives. However, although deprecated, auto_ptr has been used for years and may be your only choice if your compiler doesn’t support the other two.

Using Smart Pointers

These three smart pointer templates (auto_ptr, unique_ptr, and shared_ptr ) each defines a pointer-like object intended to be assigned an address obtained (directly or indirectly) by new. When the smart pointer expires, its destructor uses delete to free the memory. Thus, if you assign an address returned by new to one of these objects, you don’t have to remember to free the memory later; it will be freed automatically when the smart pointer object expires. Figure 16.2 illustrates the behavioral difference between auto_ptr and a regular pointer. The shared_ptr and unique_ptr share the same behavior in this situation.

Figure 16.2. A regular pointer versus auto_ptr.

To create one of these smart pointer objects, you include the memory header file, which includes the template definitions. Then you use the usual template syntax to instantiate the kind of pointer you require. The auto_ptr template, for instance, includes the following constructor:

template class auto_ptr {

public:

    explicit auto_ptr(X* p =0) throw();

...};

(The throw() notation, recall, means this constructor doesn’t throw an exception. Like auto_ptr, it is deprecated.) Thus, asking for an auto_ptr object of type X gives you an auto_ptr object that points to type X:

auto_ptr pd(new double);  // pd an auto_ptr to double

                                  // (use in place of double * pd)

auto_ptr ps(new string);  // ps an auto_ptr to string

                                  // (use in place of string * ps)

Here new double is a pointer returned by new to a newly allocated chunk of memory. It is the argument to the auto_ptr constructor; that is, it is the actual argument corresponding to the formal parameter p in the prototype. Similarly, new string is also an actual argument for a constructor. The other two smart pointers use the same syntax:

unique_ptr pdu(new double);  // pdu an unique_ptr to double

shared_ptr pss(new string);  // pss a shared_ptr to string

Thus, to convert the remodel() function, you would follow these three steps:

1. Include the memory header file.

2. Replace the pointer-to-string with a smart pointer object that points to string.

3. Remove the delete statement.

Here’s the function with those changes made using auto_ptr:

#include

void remodel(std::string & str)

{

    std::auto_ptr ps (new std::string(str));

    ...

    if (weird_thing())

        throw exception();

    str = *ps;

    // delete ps;  NO LONGER NEEDED

    return;

}

Note that smart pointers belong to the std namespace. Listing 16.5 presents a simple program using all three of these smart pointers. (Your compiler will need to support the C++11 shared_ptr and unique_ptr classes.) Each use is placed inside a block so that the pointer expires when execution leaves the block. The Report class uses verbose methods to report when an object is created or destroyed.

Listing 16.5. smrtptrs.cpp

// smrtptrs.cpp -- using three kinds of smart pointers

// requires support of C++11 shared_ptr and unique_ptr

#include

#include

#include

class Report

{

private:

    std::string str;

public:

    Report(const std::string s) : str(s)

           { std::cout << "Object created!\n"; }

    ~Report() { std::cout << "Object deleted!\n"; }

    void comment() const { std::cout << str << "\n"; }

};

int main()

{

    {

        std::auto_ptr ps (new Report("using auto_ptr"));

        ps->comment();   // use -> to invoke a member function

    }

    {

        std::shared_ptr ps (new Report("using shared_ptr"));

        ps->comment();

    }

    {

Перейти на страницу:

Все книги серии Developer's Library

Похожие книги