-1

I create an instance of object and get a pointer to that then pass into a function. The function responsible for capturing that pointer and storing it inside an unordered_map.

I made several attempts to make it compile but none of them works.

#include <iostream>
#include <memory>
#include <unordered_map>

struct Foo {
    std::string name;
};

std::unordered_map<std::string, std::shared_ptr<Foo>> zoo;

void bar(Foo *foo) {
    zoo.emplace("zilla", std::move(std::make_shared<Foo>(foo)));
}


int main()
{
    // Normal
    Foo foo;
    foo.name = "Stackoverflow";
    
    // Get Pointer
    Foo *fuzzy = &foo;
    
    bar(fuzzy);

    return 0;
}

What should be the correct way to call make_shared in this case?

Note that I don't want to create the shared_ptr for the pointer rather the object itself.

jeffbRTC
  • 1,941
  • 10
  • 29
  • 1
    `make_shared` is not for converting some existing pointer that came from some mysterious source into a shared pointer. Shared pointers don't work this way. If you don't know where the pointer came from you can't assume by default that it can be converted into a shared pointer. It can very well be in automatic storage ***like in this case***, and after converting it into a shared pointer hillarity ensues. – Sam Varshavchik Mar 08 '21 at 14:27
  • The "make" in "make_shared" is creational - think "make me a pizza", not "make me a millionaire". (I personally think it was a mistake to choose "make" over "create" when naming these functions.) – molbdnilo Mar 08 '21 at 14:28
  • @SamVarshavchik I don't want to convert pointer to shared_ptr rather the object the pointer points into. Does dereferencing works in this case? – jeffbRTC Mar 08 '21 at 14:29
  • Why would you think it wouldn't work? Did you try it? What happened? – Sam Varshavchik Mar 08 '21 at 14:32
  • @SamVarshavchik It compiles. I mean I'm not sure about undefined behavior at runtime. – jeffbRTC Mar 08 '21 at 14:34
  • And why, specifically, are you not sure about that? What are the examples of using `make_shared` in your textbook, and how does your textbook explain what it does; which part of that explanation is unclear to you? – Sam Varshavchik Mar 08 '21 at 14:36
  • @SamVarshavchik A lot of times, Stack is enough for me and I don't use pointers most of times. The book had make_shared examples with direct objects without pointers. Understand me, I'm not comfortable enough with Pointers. So, if you say, it's legal then I will take it! – jeffbRTC Mar 08 '21 at 14:40
  • @jeffbRTC you're going to have an undefined behaviour not because of the `shared_ptr` but because of your `Foo foo`; – Moia Mar 08 '21 at 14:42
  • @Moia That's how an Object initialized. What cause an undefined behavior here? Care to elaborate? – jeffbRTC Mar 08 '21 at 14:43
  • @jeffbRTC `make_shared(arguments)`, creates a new, shareable, object of the type `type` using the constructor of `type` that matches the arguments. What you saw was creating a shareable copy of an object. – molbdnilo Mar 08 '21 at 14:48
  • @jeffbRTC that's how an object is statically initialized. When your `foo` object get out of scope, your pointers are garbage and you do have an UB. You -have to- dinamically initialize your `foo` with a `new` and then store the pointer. Using `shared_ptr` and `make_shared` behave exactly the same. I would suggest you to find a book about C++ and learn what the difference between `Foo foo;` and `Foo* foo = new Foo;` – Moia Mar 08 '21 at 14:48
  • @Moia Then my suspicion is correct. I will go with the answer on below. – jeffbRTC Mar 08 '21 at 15:02
  • Does this answer your question? [When to use "new" and when not to, in C++?](https://stackoverflow.com/questions/679571/when-to-use-new-and-when-not-to-in-c) – Moia Mar 08 '21 at 15:04
  • @Moia Not really, I was avoiding "new" so I don't think this is a duplicate but glad to know it can be used to solve the problem. – jeffbRTC Mar 08 '21 at 15:05
  • @jeffbRTC avoiding using the keyword `new` and avoid dynamic initialization are completely two different things. You weren't doing the former, you were doing the latter, that's what I'm trying to make you understand. Shared pointer is just a new with scoped managed memory. – Moia Mar 08 '21 at 15:10

2 Answers2

1

Bar should take std::shared_ptr:

void bar(std::shared_ptr<Foo> foo) {
    zoo.emplace("zilla", std::move(foo));
}

int main()
{
    // Normal
    auto foo = std::make_shared<Foo>();
    foo->name = "Stackoverflow";
    
    bar(foo);
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302
0

This is just a variant of Jarod's anwser. shared_ptr is implicitly convertible from a raw pointer so it's enough to pass the raw pointer to the function

#include <iostream>
#include <memory>
#include <unordered_map>

struct Foo {
    std::string name;
};

std::unordered_map<std::string, std::shared_ptr<Foo>> zoo;

void bar(Foo *foo) {
    zoo.emplace("zilla", foo);
}

int main()
{
    auto foo = new Foo;
    foo->name = "Stackoverflow";
    
    // zoo will take the ownership of foo   
    bar(foo);

    return 0;
}

The problem with the code is not related with shared_ptr at all. Since you're not dynamically initializing your object with a new (or a make_shared) but with

Foo foo;

When the scope of where foo is initialized ends, foo is destructed and any pointer you're referring to become garbage, and you will have an undefined behaviour.

About dynamic initialization I'd suggest this Stackoverflow post

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Moia
  • 2,216
  • 1
  • 12
  • 34
  • That variant is **dangerous**, as ownership transfer is implicit and not visible. – Jarod42 Mar 09 '21 at 11:46
  • @Jarod42 I agree with you. I posted it with the sole purpose to show how it works, since he didn't have clear about dynamic memory more than how using a shared_ptr – Moia Mar 09 '21 at 13:04
  • Not sure that showing bad (as dangerous) (even if working) code, especially to beginners, as solution is good, even more without warning about the danger/pitfall. – Jarod42 Mar 09 '21 at 13:09