Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a boost::weak_intrusive_pointer?

For legacy reasons I need to use intrusive pointers, as I need the ability to convert raw pointers to smart pointers.

However I noticed there is no weak intrusive pointer for boost. I did find a talk about it on the boost thread list, however nothing concrete.

Does anyone know of a thread safe implementation of weak intrusive pointer?

Thanks Rich

like image 445
Rich Avatar asked Mar 08 '10 09:03

Rich


People also ask

What is boost intrusive_ptr?

The intrusive_ptr class template stores a pointer to an object with an embedded reference count. Every new intrusive_ptr instance increments the reference count by using an unqualified call to the function intrusive_ptr_add_ref , passing it the pointer as an argument.

Why intrusive_ ptr?

The main reasons to use intrusive_ptr are: Some existing frameworks or OSes provide objects with embedded reference counts; The memory footprint of intrusive_ptr is the same as the corresponding raw pointer; intrusive_ptr<T> can be constructed from an arbitrary raw pointer of type T *.

How do you set a shared pointer to a weak pointer?

You can make a weak pointer from a shared pointer, just using assignment = e.g. bool release_channel(std::shared_ptr<abstract::channel> ch) { std::weak_ptr<abstract::channel> weak_ch = ch; //... }


3 Answers

It does not make any sense.

To elaborate: weak_ptr points to the same instance of a counter object that shared_ptr do. When the shared_ptr goes out of scope, the instance of the counter stays (with a count effectively at 0), which allows the weak_ptr instances to check that they effectively point to a freed object.

With Intrusive Counting, the counter is integrated within the object. When the count reaches 0, the object is usually either recycled or deleted... but the point is the counter is no longer available. The rationale is that this allow for a more efficient storage (1 single chunk) and greater speed (cache locality).

If you need Weak Reference counting and do not care for the benefits of intrusive counting, you can use a combination of shared_ptr and weak_ptr.

The idea is to deassociate the counter from the objects.

class Counted
{
  // bla
private:
  boost::shared_ptr<int> mCounter;
};

Now you can return weak handles:

class WeakHandle
{
public:
  explicit WeakHandle(Counted& c): mCounter(c.mCounter), mObject(&c) {}

  bool expired() const { return mCounter.expired(); }

private:
  boost::weak_ptr<int> mCounter;
  Counted* mObject;
};

Here, we deassociate the lifetime of the counter from the lifetime of the object, so that it will survive the destruction of the object... partially. Thus making the weak_ptr effectively possible.

And of course, using shared_ptr and weak_ptr this is Thread Safe ;)

like image 65
Matthieu M. Avatar answered Oct 11 '22 02:10

Matthieu M.


I didn't really like either of the previous answers so:

No, I don't know of an implementation, but I think it is possible. The standard implementation of the shared_ptr holds two reference counts, one for the "strong" and one for the "weak" references, and a pointer to the referent. In an intrusive_ptr implementation the strong count needs to be part of the object, but the weak can't be. So, it seems like you could create a "weakable" intrusive_ptr.

Define a weak pointer helper:

template<class X>
class intrusive_ptr_weak_helper {
    long weak_ref_count;
    X *target_instance;
};

Then record that into the object beside the reference count:

struct X {
    ...
    intrusive_ptr_weak_helper *ref_weak_helper;
    ...
    long ref_count;
    ...
};

When constructing X:

ref_count = 0;
ref_weak_helper = NULL;

The "strong" pointer, intrusive_strong_ptr, is identical to intrusive_ptr, until deletion occurs. When the strong ref count goes to zero (before deletion occurs):

if (ref_weak_helper != NULL) {
    if (ref_weak_helper->weak_ref_count == 0)
        delete ref_weak_helper;
    else
        ref_weak_helper->target_instance = NULL;
}

The "weak" version, intrusive_weak_ptr, records the pointer to the weak helper, manipulating that reference count, and accessing the target object via the target_instance pointer. When the weak_ref_count decrements to zero the status of target_instance determines whether the helper is deleted or not.

There are many details missing (concurrency concerns for instance) but this is a mixing of the shared_ptr and the intrusive_ptr. It maintains the basic benefits of the intrusive_ptr (cache optimization, reuse of 3rd party intrusive (strong) ref count, strong and weak pointer stand-ins are pointer sized) while adding extra work mainly in the weak reference path.

like image 6
Speed8ump Avatar answered Oct 11 '22 04:10

Speed8ump


Current implementation of intrusive pointer is using reference counter. So deleting object delete also delete the counter, so weak_intrusive_pointer will never know that the object was deleted.

If you need to get weak_ptr from this, you probably search boost::enable_shared_from_this<T>.

like image 4
Arpegius Avatar answered Oct 11 '22 04:10

Arpegius