vendredi 30 octobre 2015

Idiomatic C++ syntax for "maybe-move" parameter passing

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