30

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
Null
  • 1,950
  • 9
  • 30
  • 33
Bill Cheatham
  • 11,396
  • 17
  • 69
  • 104

4 Answers4

45

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);
111111
  • 15,686
  • 6
  • 47
  • 62
  • 1
    There, I combined your two answers. – Omnifarious Dec 11 '11 at 21:44
  • 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. – Tom Anderson Oct 19 '18 at 17:40
33

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);
Community
  • 1
  • 1
Omnifarious
  • 54,333
  • 19
  • 131
  • 194
16

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;
Luc Danton
  • 34,649
  • 6
  • 70
  • 114
  • 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. – Omnifarious Dec 11 '11 at 19:01
  • @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. – Yakov Galka Dec 11 '11 at 19:03
  • 2
    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. – 111111 Dec 11 '11 at 19:05
  • @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. – Omnifarious Dec 11 '11 at 19:10
  • 1
    @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. – 111111 Dec 11 '11 at 19:15
  • There, I combined your two answers. – Omnifarious Dec 11 '11 at 21:44
  • 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. – Matthew Smith Dec 03 '12 at 05:52
  • @MattSmith `noop_deleter` is here not the name of the type, but is an object of that (anonymous) type. – Luc Danton Dec 03 '12 at 06:55
8

You cannot create a boost::shared_ptr for an existing variable. Items stored in a boost::shared_ptr are stored at creation.

You can however make a boost::shared_ptr that is a copy of an existing variable.

For example

int a = 3; // Existing variable
boost::shared_ptr<int> aCopy = boost::make_shared<int>(a); //Create copy with value of a

Note that you will need to include <boost/make_shared.hpp> for make_shared.