Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using try_emplace with a shared_ptr

Tags:

c++

So I have a std::unordered_map<std::string, std::shared_ptr<T>> and I'd like to use try_emplace to add/reference elements. Previously, it was simply a std::unordered_map<std::string, T> and T has a constructor which just takes a std::string, so I was using myMap.try_emplace(myString, myString).first->second to reference the T and create it if necessary.

However, if I simply change it to myMap.try_emplace(myString, std::make_shared<T>(myString)).first->second, it, of course, constructs the T every time.

What's the most idiomatic way to get around this? To clarify, I'd like to construct the object on the heap with a shared pointer and insert the shared pointer into the unordered map if and only if there is not already a matching element in the map.

like image 824
River Tam Avatar asked Jun 19 '18 14:06

River Tam


People also ask

What happens when shared_ptr goes out of scope?

All the instances point to the same object, and share access to one "control block" that increments and decrements the reference count whenever a new shared_ptr is added, goes out of scope, or is reset. When the reference count reaches zero, the control block deletes the memory resource and itself.

What is the difference between Make_shared and shared_ptr?

The difference is that std::make_shared performs one heap-allocation, whereas calling the std::shared_ptr constructor performs two.

What is the purpose of the shared_ptr <> template?

std::shared_ptr is a smart pointer that retains shared ownership of an object through a pointer.


1 Answers

You can use operator[] instead:

auto &ptr = map[ key ];
if( !ptr ) ptr = std::make_shared<T>( myString );

Note: this solution came with assumption that you do not want to keep default constructed std::shared_ptr in the map. If that is the case, then you would need to use little more verbose code with try_emplace:

auto p = map.try_emplace( key, nullptr );
if( p.second ) p.first->second = std::make_shared<T>( myString );
else {
    if( !p.first->second ) { // handle nullptr }
}
auto &ptr = p.first->second;
like image 117
Slava Avatar answered Oct 26 '22 23:10

Slava