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