Search code examples
c++dictionaryshared-ptr

How to handle a map of shared_ptr with move constructor correctly?


Consider I have a container std::map<int, std::shared_ptr<MyClass>> and I want to fill it in external function and avoid coping of its contents. So I have

typedef Container std::map<int, std::shared_ptr<MyClass>>

Container&& f(){
    Container bar;
    auto foo = std::shared_ptr<MyClass>(new MyClass());
    bar.insert(std::make_pair(0,foo));
    std::cout<<bar.at(1)->print_smth<<'\n'; //This works
    return std::move(bar);
}

int main(){
    Container baz(f());
    std::cout<<bar.at(1)->print_smth<<'\n'; //This doesn't
    // Container baz has element 1, but shared_ptr is invalidated, because it has 0 references.

}

If I use conventional copy constructor everything works as expected.


Solution

  • This is far too complicated. Why not just say this:

    int main()
    {
        Container baz { { 0, std::make_shared<MyClass>() } };
    
        // ...
    }
    

    If you absolutely must go with the helper function, you have to return an object, not a dangling reference. Something like this:

    Container f()
    {
        return Container { { 0, std::make_shared<MyClass>() } };
    }
    

    It's hard to indulge anything more pedestrian than this, but one final, never-to-be-used-at-home version:

    Container f()
    {
       Container bar;
       auto p = std::make_shared<MyClass>;
    
       bar[0] = p;                        // Method #1
       // ---- ALTERNATIVELY ---
       bar.insert(std::make_pair(0, p));  // Method #2
       // ---- ALTERNATIVELY ---
       bar.emplace(0, p);                 // Method #3
    
       return bar;
    }