views:

723

answers:

3

We've pretty much moved over to using boost::shared_ptr in all of our code, however we still have some isolated cases where we use std::auto_ptr, including singleton classes:

template < typename TYPE >
class SharedSingleton
{
public: 
    static TYPE& Instance()
    {
        if (_ptrInstance.get() == NULL)
            _ptrInstance.reset(new TYPE);
        return *_ptrInstance;
    }

protected: 
    SharedSingleton() {};

private:
    static std::auto_ptr < TYPE > _ptrInstance;
};

I've been told that there's a very good reason why this hasn't been made a shared_ptr, but for the life of me I can't understand why? I know that auto_ptr will eventually get marked as depreciated in the next standard, so I'd like to know what/how I can replace this implementation.

Also, are there any other reasons why you'd consider using an auto_ptr instead of a shared_ptr? And do you see any problems moving to shared_ptr in the future?


Edit:

  1. So in answer to "can I safely replace auto_ptr with shared_ptr in the above code", the answer is yes - however I'll take a small performance hit.
  2. When auto_ptr is eventually marked as depreciated and we move over to std::shared_ptr, we'll need to thoroughly test our code to make sure we're abiding by the different ownership semantics.
A: 

auto_ptr is the only kind of smart pointer I use. I use it because I don't use Boost, and because I generally prefer my business/application-oriented classes to explicitly define deletion semantics and order, rather than depend on collections of, or individual, smart pointers.

anon
Smart pointers are useful tools for writing safe and efficient code in C++. It is very hard to write exception neutral, memory leak free programs without them.
TimW
auto_ptr (which I've already said I use) IS a smart pointer!
anon
Well auto_ptr is not that smart ;-) You can't handle shared resources with it. So you probably have written, or should have, your own ref counted pointer for that and that is exactly what shared_ptr is doing for you. I find it very bad advice not to use any smart pointer except auto_ptr. I would advice exactly the opposite because auto_ptr has been given two responsibilities: ensuring that it is properly destroyed no matter how we leave the scope and to safely transfer objects from one location to another. shared_ptr or unique_ptr should be used instead.
TimW
I don't believe in shared resources. A resource should belong to one instance of one class. And I didn't give the advice to not use any other kind of smart pointer - I described what I do.
anon
And what about cross cutting concerns, context objects, shared data, optimization strategies, hardware interfaces, ... - Isn't describing what you do and giving advice the same :S
TimW
+15  A: 

auto_ptr and shared_ptr solve entirely different problems. One does not replace the other.

auto_ptr is a thin wrapper around pointers to implement RAII semantics, so that resources are always released, even when facing exceptions. auto_ptr does not perform any reference counting or the like at all, it does not make multiple pointers point to the same object when creating copies. In fact, it's very different. auto_ptr is one of the few classes where the assignment operator modifies the source object. Consider this shameless plug from the auto_ptr wikipedia page:

int *i = new int;
auto_ptr<int> x(i);
auto_ptr<int> y;

y = x;

cout << x.get() << endl; // Print NULL
cout << y.get() << endl; // Print non-NULL address i

Note how executing

y = x;

modifies not only y but also x.

The boost::shared_ptr template makes it easy to handle multiple pointers to the same object, and the object is only deleted after the last reference to it went out of scope. This feature is not useful in your scenario, which (attempts to) implement a Singleton. In your scenario, there's always either 0 references to 1 reference to the only object of the class, if any.

In essence, auto_ptr objects and shared_ptr objects have entirely different semantics (that's why you cannot use the former in containers, but doing so with the latter is fine), and I sure hope you have good tests to catch any regressions you introduced while porting your code. :-}

Frerich Raabe
+6  A: 

Others have answered why this code uses an auto_ptr instead of a shared_ptr. To address your other questions:

What/how I can replace this implementation?

Use either boost::scoped_ptr or unique_ptr (available in both Boost and the new C++ standard). Both scoped_ptr and unique_ptr provide strict ownership (and no reference counting overhead), andthey avoid the surprising delete-on-copy semantics of auto_ptr.

Also, are there any other reasons why you'd consider using an auto_ptr instead of a shared_ptr? And do you see any problems moving to shared_ptr in the future?

Personally, I would not use an auto_ptr. Delete-on-copy is just too non-intuitive. Herb Sutter seems to agree. Switching to scoped_ptr, unique_ptr, or shared_ptr should offer no problems. Specifically, shared_ptr should be a drop-in replacement if you don't care about the reference counting overhead. scoped_ptr is a drop-in replacement if you aren't using auto_ptr's transfer-of-ownership capabilities. If you are using transfer-of-ownership, then unique_ptr is almost a drop-in replacement, except that you need to instead explicitly call move to transfer ownership. See here for an example.

Josh Kelley