Getting a boost::shared_ptr for this

C++Boost

C++ Problem Overview


I am making extensive use of boost:shared_ptr in my code. In fact, most of the objects that are allocated on the heap are held by a shared_ptr. Unfortunately this means that I can't pass this into any function that takes a shared_ptr. Consider this code:

void bar(boost::shared_ptr<Foo> pFoo)
{
    ...
}

void Foo::someFunction()
{
    bar(this);
}

There are two problems here. First, this won't compile because the T* constructor for shared_ptr is explicit. Second, if I force it to build with bar(boost::shared_ptr<Foo>(this)) I will have created a second shared pointer to my object that will eventually lead to a double-delete.

This brings me to my question: Is there any standard pattern for getting a copy of the existing shared pointer you know exists from inside a method on one of those objects? Is using intrusive reference counting my only option here?

C++ Solutions


Solution 1 - C++

You can derive from enable_shared_from_this and then you can use "shared_from_this()" instead of "this" to spawn a shared pointer to your own self object.

Example in the link:

#include <boost/enable_shared_from_this.hpp>

class Y: public boost::enable_shared_from_this<Y>
{
public:

    shared_ptr<Y> f()
    {
        return shared_from_this();
    }
}

int main()
{
    shared_ptr<Y> p(new Y);
    shared_ptr<Y> q = p->f();
    assert(p == q);
    assert(!(p < q || q < p)); // p and q must share ownership
}

It's a good idea when spawning threads from a member function to boost::bind to a shared_from_this() instead of this. It will ensure that the object is not released.

Solution 2 - C++

Just use a raw pointer for your function parameter instead of the shared_ptr. The purpose of a smart pointer is to control the lifetime of the object, but the object lifetime is already guaranteed by C++ scoping rules: it will exist for at least as long as the end of your function. That is, the calling code can't possibly delete the object before your function returns; thus the safety of a "dumb" pointer is guaranteed, as long as you don't try to delete the object inside your function.

The only time you need to pass a shared_ptr into a function is when you want to pass ownership of the object to the function, or want the function to make a copy of the pointer.

Solution 3 - C++

boost has a solution for this use case, check enable_shared_from_this

Solution 4 - C++

Are you really making more shared copies of pFoo inside bar? If you aren't doing anything crazy inside, just do this:


void bar(Foo &foo)
{
// ...
}

Solution 5 - C++

With C++11 shared_ptr and enable_shared_from_this is now in the standard library. The latter is, as the name suggests, for this case exactly.

http://en.cppreference.com/w/cpp/memory/shared_ptr

http://en.cppreference.com/w/cpp/memory/enable_shared_from_this

Example bases on that in the links above:

struct Good: std::enable_shared_from_this<Good>{
    std::shared_ptr<Good> getptr() {
        return shared_from_this();
    }
};

use:

std::shared_ptr<Good> gp1(new Good);
std::shared_ptr<Good> gp2 = gp1->getptr();
std::cout << "gp2.use_count() = " << gp2.use_count() << '\n';

Solution 6 - C++

The function accepting a pointer wants to do one of two behaviors:

  • Own the object being passed in, and delete it when it goes out of scope. In this case, you can just accept X* and immediately wrap a scoped_ptr around that object (in the function body). This will work to accept "this" or, in general, any heap-allocated object.
  • Share a pointer (don't own it) to the object being passed in. In this case you do not want to use a scoped_ptr at all, since you don't want to delete the object at the end of your function. In this case, what you theoretically want is a shared_ptr (I've seen it called a linked_ptr elsewhere). The boost library has a version of shared_ptr, and this is also recommended in Scott Meyers' Effective C++ book (item 18 in the 3rd edition).

Edit: Oops I slightly misread the question, and I now see this answer is not exactly addressing the question. I'll leave it up anyway, in case this might be helpful for anyone working on similar code.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJoe LudwigView Question on Stackoverflow
Solution 1 - C++Brian R. BondyView Answer on Stackoverflow
Solution 2 - C++Mark RansomView Answer on Stackoverflow
Solution 3 - C++David PierreView Answer on Stackoverflow
Solution 4 - C++Greg RogersView Answer on Stackoverflow
Solution 5 - C++Johan LundbergView Answer on Stackoverflow
Solution 6 - C++TylerView Answer on Stackoverflow