Consider a map
-like type with slightly different behavior on the emplace
operation: While it accepts Key&&
and Val&&
arguments, it guarantees me that any argument I pass it will remain unchanged if the key is not inserted.
I want to implement an insert_or_update
type function (I realize this is not the way you would actually do it, but stick with me for an example).
my_map_type::iterator iter;
bool inserted_new;
std::tie(iter, inserted_new) = my_map.emplace(std::move(key), std::move(val));
if (!inserted_new)
iter->second = std::move(val);
Someone looking at this code will think there is a bug: I am using val
after I have already said std::move(val)
.
The most reasonable thoughts I have are to change emplace
to return an optional<Val>
instead of just a bool
. If the key is not inserted, it will be returned to you.
my_map_type::iterator iter;
std::optional<Val> returned_val;
std::tie(iter, returned_val) = my_map.emplace(std::move(key), std::move(val));
if (returned_val)
iter->second = std::move(*returned_val);
The problem with this solution is performance. The most obvious issue is that it only works reasonably if moving your Val
is absurdly cheap. Another problem is that under -O3, my original example does not touch the stack, while the latter puts returned_val
on it (when Val = std::uint64_t
on a 64-bit Linux machine with GCC 5.2).
Question: Is there a way to maintain the safety of my latter option while still getting the performance benefits of the former?
Aucun commentaire:
Enregistrer un commentaire