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

        ps->comment();

    }

    return 0;

}

Here is the output:

Object created!

using auto_ptr

Object deleted!

Object created!

using shared_ptr

Object deleted!

Object created!

using unique_ptr

Object deleted!

Each of these classes has an explicit constructor taking a pointer as an argument. Thus, there is no automatic type cast from a pointer to a smart pointer object:

shared_ptr pd;

double *p_reg = new double;

pd = p_reg;                         // not allowed (implicit conversion)

pd = shared_ptr(p_reg);     // allowed (explicit conversion

shared_ptr pshared = p_reg; // not allowed (implicit conversion)

shared_ptr pshared(p_reg);  // allowed (explicit conversion)

The smart pointer template classes are defined so that in most respects a smart pointer object acts like a regular pointer. For example, given that ps is a smart pointer object, you can dereference it (*ps), use it to access structure members (ps->puffIndex), and assign it to a regular pointer that points to the same type. You can also assign one smart pointer object to another of the same type, but that raises an issue that the next section faces.

But first, here’s something you should avoid with all three of these smart pointers:

string vacation("I wandered lonely as a cloud.");

shared_ptr pvac(&vacation);  // NO!

When pvac expires, the program would apply the delete operator to non-heap memory, which is wrong.

If Listing 16.5 represents the pinnacle of your programming aspirations, any of these three smart pointers will serve your purposes. But there is more to the story.

Smart Pointer Considerations

Why three smart pointers? (Actually, there are four, but we won’t discuss weak_ptr.) And why is auto_ptr being deprecated?

Begin by considering assignment:

auto_ptr ps (new string("I reigned lonely as a cloud."));

auto_ptr vocation;

vocation = ps;

What should the assignment statement accomplish? If ps and vocation were ordinary pointers, the result would be two pointers pointing to the same string object. That is not acceptable here because the program would wind up attempting to delete the same object twice—once when ps expires, and once when vocation expires. There are ways to avoid this problem:

• Define the assignment operator so that it makes a deep copy. This results in two pointers pointing to two distinct objects, one of which is a copy of the other.

• Institute the concept of ownership, with only one smart pointer allowed to own a particular object. Only if the smart pointer owns the object will its destructor delete the object. Then have assignment transfer ownership. This is the strategy used for auto_ptr and for unique_ptr, although unique_ptr is somewhat more restrictive.

• Create an even smarter pointer that keeps track of how many smart pointers refer to a particular object. This is called reference counting. Assignment, for example, would increase the count by one, and the expiration of a pointer would decrease the count by one. Only when the final pointer expires would delete be invoked. This is the shared_ptr strategy.

The same strategies we’ve discussed for assignment, of course, would also apply to the copy constructors.

Each approach has its uses. Listing 16.6 shows an example for which auto_ptr is poorly suited.

Listing 16.6. fowl.cpp

// fowl.cpp  -- auto_ptr a poor choice

#include

#include

#include

int main()

{

    using namespace std;

    auto_ptr films[5] =

    {

        auto_ptr (new string("Fowl Balls")),

        auto_ptr (new string("Duck Walks")),

        auto_ptr (new string("Chicken Runs")),

        auto_ptr (new string("Turkey Errors")),

        auto_ptr (new string("Goose Eggs"))

    };

    auto_ptr pwin;

    pwin = films[2];   // films[2] loses ownership

    cout << "The nominees for best avian baseball film are\n";

    for (int i = 0; i < 5; i++)

        cout << *films[i] << endl;

    cout << "The winner is " << *pwin << "!\n";

    cin.get();

    return 0;

}

Here is some sample output:

The nominees for best avian baseball film are

Fowl Balls

Duck Walks

Segmentation fault (core dumped)

The “core dumped” message should help fix in your memory that a misused auto_ptr can be a problem. (The behavior for this sort of code is undefined, so you might encounter different behavior, depending on your system.) Here the problem is that the following statement transfers ownership from films[2] to pwin:

pwin = films[2];   // films[2] loses ownership

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

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

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