Create a boost::shared_ptr to an existing variable

44,861

Solution 1

although you should put the variable into a managed pointer on it's creation to do it from an existing pointer.

int *a=new int;
boost::shared_ptr<int> a_ptr(a);

That said you most definitely do not want to be putting stack variables into shared_ptr BAD THINGS WILL HAPPEN

If for some reason a function takes shared_ptr and you only have a stack varaible you are better off doing this:

int a=9;
boost::shared_ptr<int> a_ptr=boost::make_shared(a);

See here:

http://www.boost.org/doc/libs/1_43_0/libs/smart_ptr/make_shared.html

also it is worth noting that shared_ptr is in the c++11 standard if you are able using that. You can use auto in combination with make_shared like Herb Sutter notes in the build talk.

#include <memory>

int a=9;
auto a_ptr=std::make_shared(9);

Solution 2

First, you have an error because shared_ptr's will not automatically convert from a pointer of the appropriate type. You have to explicitly state that's what you want to do:

int a = 3;
::boost::shared_ptr< int > a_ptr(&a); // DO NOT DO THIS!

You have another problem though. Imagine the effect of this code:

int a = 3;
delete &a;

In the first example I gave, this will inevitably happen, even if it's not quite so direct. shared_ptr's whole reason for existence is deleting things when all the pointers to it go away. This, of course, will cause all manner of strange behavior.

You have two ways of dealing with this issue. One is to create something that can be deleted. The other is to make sure that shared_ptr doesn't actually delete the thing it points to. There are pros and cons to each.

Making something that can be deleted:

Pros:

  • Simple and easy.
  • You don't have to worry about object lifetimes.

Cons:

  • A bit on the slow side, since it will involve a heap allocation or two.
  • The resulting shared_ptr will refer to a copy, so modifications to a will not be reflected in the value of the thing it points to.

How to do it:

::boost::shared_ptr<int> a_ptr(::boost::make_shared(a));

This is rather similar to (and this will also work):

::boost::shared_ptr<int> a_ptr(new int(a));

But it's slightly more efficient. ::boost::make_shared does some magic to allocate the reference count and the object in contiguous memory which saves on calls to the allocator and improves locality of reference.

Making it so that shared_ptr doesn't actually delete what it points to:

Pros:

  • Faster, though it still involves a heap allocation for the reference count
  • Directly addresses the issue at hand (the thing you're pointing to can't be deleted).
  • The shared_ptr refers to a, so if you change its value things that access it through the pointer will see the new value.

Cons:

  • Requires knowing a bit more about how shared_ptr works, which means the people reading your code have to know too.
  • If the thing you're pointing to goes out of scope before all shared_ptr's that point to it do, then those pointers become dangling, and that's bad.
  • The previous point makes this a very risky solution. I would generally avoid it.

How to do it:

Somewhere outside the function (probably in an anonymous namespace):

void do_nothing_deleter(int *)
{
    return;
}

And then in the function:

int a = 3;
::boost::shared_ptr a_ptr(&a, do_nothing_deleter);

Solution 3

What you wrote won't work because the constructor of shared_ptr you're looking for is explicit, so you'd need to write it like so

boost::shared_ptr<int> a_ptr(&a); // Don't do that!

The problem with that however, is that delete will be called on the stored value of a_ptr. Since in your example a has automatic storage duration, this is very bad. So we pass in a custom deleter too:

boost::shared_ptr<int> a_ptr(&a, noop_deleter);

An implementation of noop_deleter for C++11:

auto noop_deleter = [](int*) {};

C++03 version:

// Can't be put in local scope
struct {
    void
    operator()(int*) const
    {}
} noop_deleter;
Share:
44,861
Bill Cheatham
Author by

Bill Cheatham

Computer vision, graphics and machine learning.

Updated on April 05, 2020

Comments

  • Bill Cheatham
    Bill Cheatham about 4 years

    I have an existing variable, e.g.

    int a = 3;
    

    How can I now create a boost::shared_ptr to a? For example:

    boost::shared_ptr< int > a_ptr = &a; // this doesn't work
    
  • Omnifarious
    Omnifarious over 12 years
    This is a really great piece of knowledge. I think other people's make_shared ideas are easier to cope with, but I really think this is the best answer.
  • Yakov Galka
    Yakov Galka over 12 years
    @Omnifarious: this is the only correct answer, as the question is about creating a shared_ptr to an existing variable, not a copy of it. Also making noop_deleter a template will be better.
  • 111111
    111111 over 12 years
    Whilst this is an interesting piece of information I would highly recommend that this isn't done. The very fact that a shared_ptr is used is because you don't know when the object will be destroyed. However you know how long the object will last on the stack. So even if you know exactly when it will destroy there is no point do this because you can always assign back to the stack variable.
  • Omnifarious
    Omnifarious over 12 years
    @111111: There are pros and cons. The huge risk this approach runs is that the shared_ptr won't go away before the stack variable does. But it's MUCH more efficient than creating a copy on the heap. And ybungalobill is correct, this is the only technically correct answer to the question as stated. It did not deserve a downvote.
  • 111111
    111111 over 12 years
    @Omnifarious hmmm fair enough, I perhaps shouldn't of downvoted in hindsight. But creating a shared_ptr to stack variable is risky business. If you know exactly how long the varaible is require for you probably wouldn't be using a shared_ptr. Because he knows how long he want it to last for (ie when it contains his answer he can then just reassign to stack variable.) - if you edit the answer ill retract the downvote BTW.
  • Omnifarious
    Omnifarious over 12 years
    There, I combined your two answers.
  • Omnifarious
    Omnifarious over 12 years
    There, I combined your two answers.
  • Matthew Smith
    Matthew Smith over 11 years
    I had a few syntax problems using your example with linux g++. I had to put the name of the noop_deleter struct before the braces. I had to put parentheses to instantiate the noop_deleter when passing it to the shared_ptr constructor as well.
  • Luc Danton
    Luc Danton over 11 years
    @MattSmith noop_deleter is here not the name of the type, but is an object of that (anonymous) type.
  • Tom Anderson
    Tom Anderson over 5 years
    The first suggestion is really dangerous - when the shared_ptr dies, it will delete the pointed-to object, even if the original pointer still exists. You must use a no-op deleter in this situation - see Luc Danton's answer.