C++ Logo


Advanced search

Re: std::take(obj), aka std::exchange(obj, {})

From: Jason McKesson <jmckesson_at_[hidden]>
Date: Thu, 24 Sep 2020 19:21:49 -0400
On Thu, Sep 24, 2020 at 6:16 PM Arthur O'Dwyer via Std-Proposals
<std-proposals_at_[hidden]> wrote:
> On Thu, Sep 24, 2020 at 5:55 PM Giuseppe D'Angelo via Std-Proposals <std-proposals_at_[hidden]> wrote:
>> Hello,
>> I'm attaching the first draft for a proposal for std::take, a function
>> that moves from an object, resets it to its default constructed state,
>> and returns the old value.
> I don't understand how this is different from
> newobj = std::exchange(obj, {});
> Even after reading the motivation... is it just to save a few characters?
> newobj = std::exchange(obj, {}); // longer
> newobj = std::take(obj); // shorter
> The big costs of `std::exchange(obj, {})` as far as I'm concerned are that you have to default-construct a whole T object, pass std::exchange a reference to that object, call the assignment operator which has to conditionally free the old resource, and finally destroy the temporary T object (which has to conditionally free the resource). I can see how it would be beneficial to coalesce some of these operations into a tighter package like std::take. But I don't see how your suggested implementation of std::take actually helps. You're still constructing a temporary T, calling the assignment operator, and calling the destructor of the temporary.
> // std::take of a string
> {
> std::string temp{};
> newobj = std::move(obj);
> obj = std::move(temp);
> } // temp.~string();
> // what you want instead
> newobj = std::move(obj);
> obj.clear();
> Here's the difference in codegen: https://godbolt.org/z/n54arb
> So the $64,000 question is: How do you get the good codegen?
> If you can't get the good codegen, then I don't see the point of making a wrapper around std::exchange(obj, {}). It's already short and clear enough — certainly clearer than std::take(obj), this year, since people have already had 20 years to learn what std::exchange means. You'll have to teach them what std::take means, and (more importantly) why to use it. If you can't explain why to use it, then it's not a good idea. "It produces better codegen" would be a great explanation... but how do we get from here to there?

If we get some form of destructive move, then there's a possibility
for `take` to have improved performance over `exchange`. `take` could
destructive-move into the return value, then simply reconstruct the
original object via `new (&old_obj) T{}`. This means that there's no
temporary to assign or destroy.

Obviously `exchange` can't do that.

But since there are circumstances for some objects where you can't use
the previous name of them when creating an object in its original
place, that may be problematic.

Received on 2020-09-24 18:21:59