How to Release Pointer from Boost::Shared_Ptr

How to release pointer from boost::shared_ptr?

You need to use a deleter that you can request not to delete the underlying pointer.

See this answer (which has been marked as a duplicate of this question) for more information.

boost::shared_ptr from pointer

If you have a shared_ptr managing a pointer and then create another shared_ptr managing the same pointer (NOT copying the original shared_ptr), you end up with two managers for the same resource. When one of the two reach a reference count of 0, it will delete the object and the other shared_ptr will point to deleted memory with all that follows.

Deleting content of a boost::shared_ptr

It depends what you want to do with ptr afterwards.

If you need to reassign it to point to a new value, then that's what the code does. If you need to explicitly invalidate it, then that's what reset() does. If it's a class member that will be implicitly destroyed by the destructor, then there's probably no need to do anything, unless you have some weird destruction order requirements.

Without more context, it's impossible to say which is correct.

UPDATE: since you say this is not actually in a destructor, but a member function intended to leave the object in a weird half-destroyed state, it depends on how that weird state is specified. If it requires an empty pointer, then reset it; if it requires a valid pointer, but not to whatever was previously being shared, then reassign it. Better still, eliminate this state entirely to give the object stronger validity guarantees.

Detach a pointer from a shared_ptr?

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.

How to intentionally delete a boost::shared_ptr?

You just do

ptr.reset();

See the shared_ptr manual. It is equivalent to

shared_ptr<T>().swap(ptr)

You call reset on every smart pointer that should not reference the object anymore. The last such reset (or any other action that causes the reference count drop to zero, actually) will cause the object to be free'ed using the deleter automatically.

Maybe you are interested in the Smart Pointer Programming Techniques. It has an entry about delayed deallocation.

Question on converting boost shared pointer to standard shared pointer

The shared pointer created has a destroy function object (deleter) that has state. In particular it has a copy of the boost shared ptr.

The destruction action does nothing, it is the destruction of deleter that cleans up the boost shared ptr.

There is a problem though:

Does the C++ standard fully specify cleanup of the deleter itself? E.g. it might stay around when only weak references remain?
The standard does guarantee a minimum lifetime for the deleter, leaving the possibility that lives longer than that.

Destroying the destruction object is not specified to occur in either the constructor of std::shared_ptr nor the destructor of std::shared_ptr. It would be reasonable to destroy it either after it is called, or when the reference counting block is destroyed - in the second case, we end up with it lasting until the last weak ptr goes away.

From the draft standard:

[Note: It is unspecified whether the pointer remains valid longer than that. This can happen if the implementation doesn’t destroy the deleter until all weak_ptr instances that share ownership with p have been destroyed. — end note]

The possibility to defer destruction of the deleter is clear. So in that case we end up with shared_ptrs that doesn't destruct their element instance when we want it to be called depending on unspecified details of the C++ implementation you run it on. That is a bad idea.

Better Alternative

I would personally go with a similar trick based on the aliasing constructor instead. It is just as simple, has no additional overhead, and the semantics are actually correct:

template<class T>
std::shared_ptr<T>
as_std_shared_ptr(boost::shared_ptr<T> bp)
{
if (!bp) return nullptr;
// a std shared pointer to boost shared ptr. Yes.
auto pq = std::make_shared<boost::shared_ptr<T>>(std::move(bp));
// aliasing ctor. Hide the double shared ptr. Sneaky.
return std::shared_ptr<T>(pq, pq.get()->get());
}

This is much less of a hack than the code from the question, because lifetime
of the boost shared ptr is no longer tied to the (unspecified) lifetime of the deleter instance.

boost::shared_ptr destroy callback

You can pass a deleter function to shared ptr and write object state in this function.

template<class Y, class D> shared_ptr(Y * p, D d);

boost::shared_ptr drop-in replacement

Step 1: Build a class like this, and replace usage of boost::shared_ptr<T> with it.

template<typename T>
struct trivial_ptr {
T* t;
template<typename U>
void reset( U* p ) {t=p;}
void reset( T* p = NULL ) { t=p; }
template<typename U>
trivial_ptr<T>& operator=(trivial_shared_ptr<U>const& o) {
t = o.t;
return *t;
}
explicit trivial_ptr( T* p ):t(p) {}
...
};

this class is not intended to run, but just to compile with the correct interface. Once you have compiled, you can ensure you know what parts of the boost::shared_ptr interface you are using. (Are you using custom deleters? etc -- the problem could be harder, or easier, and the above can help test it)

Once you are there, you can work out how hard it will be to write up a shared_ptr<T> that handles multiple threads accessing the same variable at the same time.

Now, this is extremely messy. If one thread resets a given shared_ptr while another thread reads from it, the pointer read from may be completely invalid by the time the reading thread has access to it. In effect, you need to guard all access to the underlying pointer in a mutex, which is utterly impractical.

On the other hand, if what you have is multiple readers, and never a reader and a writer, you are in better shape -- in theory, you could fix the problem with the use of appropriate locks on the reference count code.

However, what you actually describe seems to involve multiple threads both reading and writing to the same variable. And that is fundamentally broken in a way that mere thread safety on the shared_ptr variable is not going to fix.



Related Topics



Leave a reply



Submit