Why not define rvalue reference to be rvalue expression?
Asked Answered
P

1

5

Let's consider the following code:

class X {
    std::vector<int> _v;
public:
    X(std::vector<int>&& v): _v(std::move(v)) {}
};

The compiler calls this constructor only for objects that can be moved. So why not just define an rvalue references to be rvalue expressions and don't write every time std::move for them?

The ctor member initialization list would look like:

_v(v)

But this would still be a move, not a copy.

Popelka answered 30/6, 2019 at 18:24 Comment(11)
Then we won't be able to move lvalues.Boutique
and if you'd like to copy it for some reason, would you need something like std::copy?Distributary
See open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3055.pdfJustly
Could you please give an example?Popelka
@MFnx yes, std::copy would be used to call copy ctorPopelka
std::move returns its argument cast to a rvalue reference. It is useless (though harmless) to call it on things that are already rvalue references.Guardian
@n.m. As I have said we wouldn't call std::move thenPopelka
Why are you calling std::move in your example? What you wrote is already equivalent to _v(v) without any "should' or "would".Guardian
@n.m. No, without std::move that code makes a copyPopelka
Arrrh sorry you are right, this was a momentary mental glitch.Guardian
Because the rvalue reference parameter has a name it is not itself considered an rvalue. std::move() basically just returns an unnamed rvalue reference, which is therefore an rvalue.Withy
T
13

While it is somewhat unfortunate to require the std::move in this common case, it was believed that an implicit move causing a run-time error in a few cases would be more harmful.

For example:

class Y
{
public:
    Y(const std::vector<int>& v);
};

class X {
    std::vector<int> v_;
    Y                y_;
public:
    X(std::vector<int>&& v): v_(v), y_(v) {}
};

In this modified example the constructor of X uses v twice. If the first use of v implicitly moved, then the second use of v would quite likely not be getting the expected value.

Thus to avoid the accidental "use after move", if it has a name, then it can be used more than once, and is thus safer to treat it as an lvalue.

Tacklind answered 30/6, 2019 at 18:41 Comment(2)
Instead of making an rvalue reference lvalue, why not introduce an std::do_not_move for such rare cases?Diecious
@Diecious what type would std::do_not_move return?Guardian

© 2022 - 2024 — McMap. All rights reserved.