Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

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();

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.

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.

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)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top