77

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?

Joe Ludwig
  • 6,756
  • 7
  • 30
  • 29
  • "_Is using intrusive reference counting my only option here?_" What's wrong with this option? – curiousguy Oct 07 '11 at 14:31
  • Maybe nothing. Depends on your circumstances. It does make your objects bigger and may not work in places where you don't have control over the classes you're keeping smartpointers to. – Joe Ludwig Oct 07 '11 at 23:15
  • enabe_shared_from_this is now in `std::` . Have a look at my answer. – Johan Lundberg Dec 25 '12 at 19:02

6 Answers6

102

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.

Malvineous
  • 25,144
  • 16
  • 116
  • 151
Brian R. Bondy
  • 339,232
  • 124
  • 596
  • 636
19

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.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • 1
    Agreed. Many times you can use foo( const Object* object_ptr ){} foo( obj.get() ); where obj is a boost::shared_ptr< Object >. Do search on the web for Herb Sutter, is a an other and article writer who has some great information about this and similar issues. – bn. Aug 13 '09 at 04:28
  • 1
    It's little beside the point, but... If you can use pointer, then (most likely) you can use reference, which is better IMO. – denis-bu Dec 26 '13 at 19:27
  • 1
    @denis-bu, except when a `NULL` pointer is a possibility. But you make a good point. – Mark Ransom Dec 26 '13 at 19:56
  • Obviously 12 years late to this, but I don't understand this answer. The type of the argument to bar is different from a raw pointer. Without the "explicit" keyword that would make passing "this" fail to compile, wouldn't the compiler try to construct the shared_ptr from the raw pointer, creating the reference count block in the process, set the reference count to 1, then on exit from bar, decrement the reference count to 0 and try to delete "this"? – Foster Boondoggle Aug 19 '20 at 14:53
  • 1
    @FosterBoondoggle my suggestion was to change the parameter type of `bar` to a raw pointer. – Mark Ransom Aug 19 '20 at 20:12
14

boost has a solution for this use case, check enable_shared_from_this

David Pierre
  • 9,459
  • 4
  • 40
  • 32
9

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)
{
    // ...
}
Greg Rogers
  • 35,641
  • 17
  • 67
  • 94
5

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';
Johan Lundberg
  • 26,184
  • 12
  • 71
  • 97
3

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.

Tyler
  • 28,498
  • 11
  • 90
  • 106