83

I have a pointer to an object. I would like to store it in two containers which both have the ownership. So I think I would be good to make it a shared_ptr of C++0x. How could I convert a raw pointer to a shared_pointer?

typedef unordered_map<string, shared_ptr<classA>>MAP1;
MAP1 map1;
classA* obj = new classA();
map1[ID] = how could I store obj in map1??

Thanks

Leslieg
  • 877
  • 1
  • 7
  • 4

2 Answers2

74

You need to make sure you don't initialize both shared_ptr objects with the same raw pointer, or it will be deleted twice. A better (but still bad) way to do it:

classA* raw_ptr = new classA;
shared_ptr<classA> my_ptr(raw_ptr);

// or shared_ptr<classA> my_ptr = raw_ptr;

// ...

shared_ptr<classA> other_ptr(my_ptr);
// or shared_ptr<classA> other_ptr = my_ptr;
// WRONG: shared_ptr<classA> other_ptr(raw_ptr);
// ALSO WRONG: shared_ptr<classA> other_ptr = raw_ptr;

WARNING: the above code shows bad practice! raw_ptr simply should not exist as a variable. If you directly initialize your smart pointers with the result of new, you reduce your risk of accidentally initializing other smart pointers incorrectly. What you should do is:

shared_ptr<classA> my_ptr(new classA);

shared_ptr<classA> other_ptr(my_ptr);

What's nice is that the code is more concise as well.

EDIT

I should probably elaborate on how it would work with a map. If you had a raw pointer and two maps, you could do something similar to what I showed above.

unordered_map<string, shared_ptr<classA> > my_map;
unordered_map<string, shared_ptr<classA> > that_guys_map;

shared_ptr<classA> my_ptr(new classA);

my_map.insert(make_pair("oi", my_ptr));
that_guys_map.insert(make_pair("oi", my_ptr));
// or my_map["oi"].reset(my_ptr);
// or my_map["oi"] = my_ptr;
// so many choices!
mabraham
  • 2,806
  • 3
  • 28
  • 25
Dawson
  • 2,673
  • 1
  • 16
  • 18
  • 7
    Don;t expose the raw pointer in a variable. By doing that you give a maintainer an easier opportunity to screw up and put the RAW pointer into another shared pointer. Just use `my_ptr(new ClassA());` That way a maintainer has to do extra work to screw things up. – Martin York Jan 12 '11 at 05:16
  • @Martin York I was just editing to include a point about that; I'll add a more explicit note. But you are correct. :) – Dawson Jan 12 '11 at 05:19
  • `// or shared_ptr my_ptr = raw_ptr;` is wrong in `std::shared_ptr`, because it should be explicit as `// or shared_ptr my_ptr(raw_ptr);`. – Justme0 May 01 '17 at 13:57
  • 5
    Actually, the best practice is make_shared<>, and avoiding new entirely. I can't remember the deep reason, something to do with if the new throws, I think it was in a Sean Parent talk. – user1997744 Dec 26 '17 at 18:07
  • @user1997744 You are nearly correct. If you use `shared_ptr my_ptr(new classA);`, (1) the `new classA` works, (2) the `new` within the `shared_ptr<>` fails, then the pointer allocated in (1) is lost. The `std::make_shared<>` handles that case properly (i.e. it has a `try/catch` block). – Alexis Wilke Mar 27 '22 at 21:19
  • I'm very late here :v but if you are maintaining old code, with functions that return allocated pointers, the bad practice is the "safest" way :( – Ivan Feb 23 '23 at 09:41
  • Comments are understandable... BUT when writing a code that has to interface with systems and your code is passed a raw pointer from software outside your control AND the specification says you must delete the pointer when done with it (which could be a long time later - then using a shared_ptr within your code, initialized with the externally provided raw pointer seems perfectly reasonable. – David V. Corbin Mar 22 '23 at 11:05
13

You can use a variety of ways, but reset() would be good:

map1[ID].reset(obj);

And to address the issue of having two maps refer to the same shared_ptr, we can have:

map2[ID] = map1[ID];

Note that the trick in general to avoid a double delete is to try to avoid raw pointers at all. Hence avoid:

classA* obj = new classA();
map1[ID].reset(obj);

but instead put the new heap object straight into a shared_ptr.

Keith
  • 6,756
  • 19
  • 23