returning a 'pointer' which is required to be held by a smart pointer
Asked Answered
H

3

9

I have a project which I would like to make more use of smart pointers. Overall, I have been successful in this goal. However, I've come across one things which I'm not sure what the "best practice" is.

Basically I would like to return a "pointer" from a function, but require that the user hold it in a smart pointer. Not only that, I don't want to mandate a particular smart pointer (shared vs. scoped).

The problem is mostly that there doesn't seem be to a proper way to upgrade a scoped_ptr to a shared_ptr (that would be the ideal solution i think). I understand why they didn't do this, as it would allow transferring of ownership which can lead to some issues like those std::auto_ptr has.

However, transferring of ownership seems like a good idea for this case. So my idea is like this:

// contrived example of factory pattern
std::auto_ptr<A> func() { return std::auto_ptr<A>(new A); }

This works "ok" since both scoped_ptr and shared_ptr have constructors which take ownership from a std::auto_ptr.

So my question is, is this good practice? Is there a better solution? The only real alternative I've been able to come up with is using a template template as the return value like this:

// similar to above example
template <template <typename> class P>
P<A> func() { return P<A>(new A); }

which actually could work well except that I think it would need some work to get it to work with a scoped_ptr too.

Thoughts?

Haig answered 10/3, 2009 at 18:21 Comment(0)
A
11

Using std::auto_ptr is the good practice, in fact such example was suggested by Bjarne Stroustrup.

The move semantics of auto_ptr gives you right tools to deal with it.

For example:

auto_ptr<Foo> make_foo()
{
    return auto_ptr<Foo>(new Foo);
}

Foo *raw_pointer=make_foo().release();
shared_ptr<Foo> shared_pointer=make_foo();
auto_ptr<Foo> auto_pointer=make_foo();

If you return shared_ptr you can't fallback to normal pointer, with auto_ptr you can. You can allways upgrade auto_ptr to shared but not other direction.

Another important point, shared_ptr uses atomic reference-counting, that is much slower that simple and yet fully efficient job that auto_ptr does.

P.S.: scoped_ptr is just version of auto_ptr for poors --- it is non-copyable and does not have default constuctor. It is more like "less confusing" version of auto_ptr, in comparison to shared_ptr it is not in tr1. Generally there no much advantages of using scoped_ptr over auto_ptr

Attain answered 10/3, 2009 at 18:56 Comment(4)
shared_ptr in the single thread build doesn't use atomic reference-counting.Serica
You right, but by default boost is build in multi-threaded version.Attain
The advantage of using scoped_ptr over auto_ptr is when you want to make it clear you aren't supposed to copy the pointer. You simply can't with scoped_ptr. It's about conveying your intentions, just like your example does with auto_ptr and transfer of ownership.Anticlockwise
Scott Meyers also has a pretty thorough article on this at aristeia.com/Papers/resourceReturnProblem.txt.Globoid
S
3

If you build a factory that's ok that you simply return a pointer. And the user of your factory can make his own decision how to and where to put this pointer.
If you need to enforce to use smart pointer you have to restrict choice as you don't want them to use "wrong" ones.
So boost::shared_ptr. But better to typedef it then to MyClassPtr or MyClass::ptr.
Still, factories they are like "new". When I want I put result of new inside of std::auto_ptr. But I don't want to be forced to call "release" all the times when I don't want smart pointer.

Serica answered 10/3, 2009 at 18:26 Comment(3)
true, but I'd like to enforce the use of a smart pointer if possible.Haig
I agree, we are all adults here. Return a naked pointer and let the user of the code decide how to best catch the return value. I believe that shared_ptr's constructor from an auto_ptr is going away (auto_ptr is going to be deprecated).Anticlockwise
when auto_ptr is depricated in C++0x, unique_ptr will be replacing it. I'd switch to returning unique_ptr then.Benenson
J
1

With C++11 you should be able to use std::unique_ptr as the other smart pointer types have constructors that take a std::unique_ptr. If you maintain an internal list of such resources then you'd probably want to use std::shared_ptr.

Jacobba answered 18/10, 2011 at 2:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.