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.
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.
The difference is that std::make_shared performs one heap-allocation, whereas calling the std::shared_ptr constructor performs two.
std::shared_ptr is a smart pointer that retains shared ownership of an object through a pointer.
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;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With