30
votes

Possible Duplicate:
How to release pointer from boost::shared_ptr?

A function of my interface returns a pointer to an object. The user is supposed to take ownership of that object. I do not want to return a Boost.shared_ptr, because I do not want to force clients to use boost. Internally however, I would like to store the pointer in a shared_ptr to prevent memory leaks in case of exceptions etc. There seems to be no way to detach a pointer from a shared pointer. Any ideas here?

5
Is it an option to return a copy of the shared object and let the smart pointer clean-up the original?TimW
Not really, the object is a videoframe in HD resolution, so copy is to expensive.Björn Pollex
Note that C++11 has std::unique_ptr which can be used for temporarily storing the pointer and releasing it on return.Adversus

5 Answers

27
votes

What you're looking for is a release function; shared_ptr doesn't have a release function. Per the Boost manual:

Q. Why doesn't shared_ptr provide a release() function?

A. shared_ptr cannot give away ownership unless it's unique() because the other copy will still destroy the object.

Consider:

shared_ptr<int> a(new int);
shared_ptr<int> b(a); // a.use_count() == b.use_count() == 2

int * p = a.release();

// Who owns p now? b will still call delete on it in its destructor.

Furthermore, the pointer returned by release() would be difficult to deallocate reliably, as the source shared_ptr could have been created with a custom deleter.

Two options you might consider:

  • You could use std::tr1::shared_ptr, which would require your users to use a C++ library implementation supporting TR1 or to use Boost; at least this would give them the option between the two.
  • You could implement your own boost::shared_ptr-like shared pointer and use that on your external interfaces.

You might also look at the discussion at this question about using boost::shared_ptr in a library's public interface.

25
votes

there's always a way :-)

There is indeed a reason why they don't provide a release() method, but it's not impossible to create one. Make your own deleter. Something on the line of (haven't actually compiled the code, but this is the general notion):

template <typename T>
class release_deleter{
public:
  release_deleter() : released_(new some_atomic_bool(false)){}
  void release() {released_->set(true);}
  void operator()(T* ptr){if(!released_->get()) delete ptr;}
private:
  shared_ptr<some_atomic_bool> released_;
}

..

shared_ptr<some_type> ptr(new some_type, release_deleter<some_type>());

..

release_deleter<some_type>* deleter = get_deleter<release_deleter<some_type>>(ptr);
deleter->release();
some_type* released_ptr = ptr.get();
11
votes

The user is supposed to take ownership of that object. I do not want to return a Boost.shared_ptr,

shared_ptr expresses shared ownership, and you want your interface to express transfer of ownership. std::auto_ptr would thus be more applicable here.

Internally however, I would like to store the pointer in a shared_ptr to prevent memory leaks in case of exceptions

Again, shared_ptr may not be the best tool for that job. To prevent leaks in the case of exceptions, scoped_ptr or auto_ptr would be better suited.

5
votes

Use a shared_ptr to a scoped_ptr to the resource (shared_ptr<scoped_ptr<Resource>>). That way you get shared_ptr's reference counting, which will automatically destroy the resource if and only if it's still attached to the scoped_ptr. But you can detach the scoped_ptr when you're ready to hand off ownership.

2
votes

As James has well covered you can't really detach a shared pointer.

Do you need multiple owners internally, or are you transferring ownership from your class to the client? In that case a std::auto_ptr might fit the bill.

If you're worried about the surprising semantics of std::auto_ptr, you could hold it internally by boost::scoped_ptr, and detach it at the point you hand it out - leaving it up to the client to manually delete it or store it in their own smart pointer.

If you do have multiple owners on your side you could use an intrusive count. Internally you could then use boost::intrusive__ptr, but hand off the raw pointer at the interface. The client can then either manually work with ref counts, or store it in a boost::intrusive_ptr themselves (but you don't make them depend on it)