36

Consider this code:

#include <iostream>
using namespace std;

void Func(int&& i) {
    ++i;
}

int main() {
    int num = 1234;
    cout << "Before: " << num << endl;
    Func(std::move(num));
    cout << "After: " << num << endl;
}

Its output is:

Before: 1234
After: 1235

Clearly, i is being modified inside Func, as it is bound to parameter i after being "converted" to an r-value reference by std::move.

Well, my point:

Moving an object means transferring ownership of resources from one object into another. However, built-in types holds no resources because they themselves are the resources. It makes no sense to transfer the resources they hold. As shown by the example, num's value is modified. Its resource, its self, is the one being modified.

Do built-in types have move semantics?

Also, Do built-in type objects after it is moved (if it is) a well-defined behavior?

Mark Garcia
  • 17,424
  • 4
  • 58
  • 94
  • 1
    According to what? >> *"Moving an object means transferring ownership of resources from one object into another. That could leave the original (source) object in an undefined state, where assignment could be the only safe and valid operation that could be used in that object. Any operations that reads the contents of those objects may return undefined values."* – Nawaz Feb 04 '13 at 02:25
  • @Nawaz According to what I've read in SO. – Mark Garcia Feb 04 '13 at 02:25
  • 3
    `std::move` doesn't move. Your example does not have a single move between the outputs. – R. Martinho Fernandes Feb 04 '13 at 02:26
  • @Mark: Does it not depend on your implementation of move-semantics? – Nawaz Feb 04 '13 at 02:26
  • @Nawaz I have committed a mistake by having those assumptions in my original post. I have edited the post but now has a different, but still closely related, question. – Mark Garcia Feb 04 '13 at 02:39
  • @R.MartinhoFernandes See ^^^^^^^^^^^^^^^^ . – Mark Garcia Feb 04 '13 at 02:39
  • 3
    [related FAQ](http://stackoverflow.com/questions/3106110/). Relevant quotes: "`std::move(some_lvalue)` casts an lvalue to an rvalue, thus *enabling* a subsequent move." and "Moving is exclusively performed by the move constructor, not by `std::move`, and not by merely binding an rvalue to an rvalue reference." – fredoverflow Feb 04 '13 at 07:30

1 Answers1

60

And so, is the one shown by the example a well-defined behavior?

Yes, the behaviour shown in the example is the only behaviour allowed by the standard. That is because std::move doesn't move. The things that move are move constructors and move assignment operators.

All std::move does is change an lvalue into an xvalue, so that it can bind to rvalue references. It does not invoke any constructor or anything else. Changing the value category happens at the type level. Nothing happens at runtime.

Rvalue references are still references: they refer to the original object. The function increments the original integer through the reference given.

If a function takes an argument by reference, no copies nor moves happen: the original object is bound to the reference.

If a function takes an argument by value, then we might have a move.

However, fundamental types don't have move constructors. Moves degrade to copies in that case.

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
  • "If a function takes an argument by reference, no copies nor moves happen: the original object is bound to the reference. If a function takes an argument by value, then we might have a move." I'm confused -- it seems exactly the opposite. If we pass by value, then the original object can't be changed, since we're just working with a copy. If we pass by reference then we CAN move: see the first example on this page. https://www.learncpp.com/cpp-tutorial/15-4-stdmove/ I'm sure I'm just misunderstanding you somehow. – Eric Auld Apr 15 '19 at 22:00
  • 1
    @EricAuld If you take an argument by value, the parameter may be move constructed from the parameter. So the original object can change. If you take an argument by reference, there is no move in the argument passing process. It is another story if you move it later. – L. F. Jul 22 '19 at 12:39
  • Is the "after" output a defined behavior or undefined behavior? I think the "after" output tries to access something(num) that has been moved. – Bin Yan Apr 19 '23 at 04:51
  • 1
    @BinYan It is well-defined behavior when you use `num` afterwards. – Jason Apr 19 '23 at 05:03