What is boost's shared_ptr(shared_ptr<Y> const & r, T * p) used for?

Viewed 2495

boost::shared_ptr has an unusual constructor

template<class Y> shared_ptr(shared_ptr<Y> const & r, T * p);

and I am a little puzzled as to what this would be useful for. Basically it shares ownership with r, but .get() will return p. not r.get()!

This means you can do something like this:

int main() {
    boost::shared_ptr<int> x(new int);
    boost::shared_ptr<int> y(x, new int);

    std::cout << x.get() << std::endl;
    std::cout << y.get() << std::endl;

    std::cout << x.use_count() << std::endl;
    std::cout << y.use_count() << std::endl;
}

And you will get this:

0x8c66008
0x8c66030
2
2

Note that the pointers are separate, but they both claim to have a use_count of 2 (since they share ownership of the same object).

So, the int owned by x will exist as long as x or y is around. And if I understand the docs correct, the second int never gets destructed. I've confirmed this with the following test program:

struct T {
    T() { std::cout << "T()" << std::endl; }
    ~T() { std::cout << "~T()" << std::endl; }
};

int main() {
    boost::shared_ptr<T> x(new T);
    boost::shared_ptr<T> y(x, new T);

    std::cout << x.get() << std::endl;
    std::cout << y.get() << std::endl;

    std::cout << x.use_count() << std::endl;
    std::cout << y.use_count() << std::endl;
}

This outputs (as expected):

T()
T()
0x96c2008
0x96c2030
2
2
~T()

So... what is the usefulness of this unusual construct which shares ownership of one pointer, but acts like another pointer (which it does not own) when used.

6 Answers

For "shared_ptr<B> b(a, dynamic_cast<B*>(a.get()));"

I think it is not the recommended way using smart pointer.

The recommended way of doing this type conversion should be:

shared_ptr<B> b(a);

Since in Boost document it is mentioned that:

shared_ptr<T> can be implicitly converted to shared_ptr<U> whenever T* can be implicitly converted to U*. In particular, shared_ptr<T> is implicitly convertible to shared_ptr<T> const, to shared_ptr<U> where U is an accessible base of T, and to shared_ptr<void>.

In addition to that, we also have dynamic_pointer_cast which could directly do conversion on Smart Pointer object and both of these two methods would be much safer than the manually casting raw pointer way.

Related