The insert/emplace interfaces to map/unordered_map are enough to do what you want: find the position, and insert if necessary. Since the mapped values here are pointers, ekatmur's response is ideal. If your values are fully-fledged objects in the map rather than pointers, you could use something like this:
Object& ResourceManager::object_named(const char *name, const Object& initialValue) {
return _object_cache.emplace(name, initialValue).first->second;
}
The values name
and initialValue
make up arguments to the key-value pair that needs to be inserted, if there is no key with the same value as name
. The emplace
returns a pair, with second
indicating whether anything was inserted (the key in name
is a new one) - we don't care about that here; and first
being the iterator pointing to the (perhaps newly created) key-value pair entry with key equivalent to the value of name
. So if the key was already there, dereferencing first
gives the original Ojbect
for the key, which has not been overwritten with initialValue
; otherwise, the key was newly inserted using the value of name
and the entry's value portion copied from initialValue
, and first
points to that.
ekatmur's response is equivalent to this:
Object& ResourceManager::object_named(const char *name) {
bool res;
auto iter = _object_cache.end();
std::tie(iter, res) = _object_cache.emplace(name, nullptr);
if (res) {
iter->second = new Object(); // we inserted a null pointer - now replace it
}
return iter->second;
}
but profits from the fact that the default-constructed pointer value created by operator[]
is null to decide whether a new Object
needs to be allocated. It's more succinct and easier to read.