0
#include <iostream>
#include<vector>

using namespace std;
int function(int &&p)
{
    cout<<"function:"<<p<<endl;

    return 0;
}
int main()
{

    int a =10;
    function(std::move(a));
    cout<<"main:"<<a<<endl;


    return 0;
}

The output I get is as below.

function:10
main:10

But shouldn't it be as below?

function:10
main:
curiousguy
  • 7,344
  • 2
  • 37
  • 52
  • Read this http://thbecker.net/articles/rvalue_references/section_01.html – Victor Gubin Jun 06 '18 at 17:17
  • 1
    moveing a fundamental type would yield a copy – kmdreko Jun 06 '18 at 17:19
  • Can you suggest how my code to change to make output main: – arjun jawalkar Jun 06 '18 at 17:21
  • 2
    there's no way to make `cout << a` print nothing, move or no move – kmdreko Jun 06 '18 at 17:23
  • 1
    A move constructor is supposed to leave a moved-from object in a [valid but unspecified state](https://stackoverflow.com/questions/12095048/what-constitutes-a-valid-state-for-a-moved-from-object-in-c11). What that is varies between types, but as a rule of thumb I just don't use a moved-from variable except to completely reassign it in some way (if at all), unless its move constructor gives me other guarantees (e.g. that of `std::vector`). – hegel5000 Jun 06 '18 at 19:08
  • Hopefully, move semantic isn't an explicit destructor call. It doesn't undeclare an object, as there is no such thing as an undeclaration. It doesn't change the scope of a name or reduces the lifetime of an object. – curiousguy Jul 02 '18 at 08:48

2 Answers2

4

The std::move technically doesn't move anything, it just gives you an rvalue reference. The actual semantics of moving something only happen because this causes overload resolution to call different functions, so:

std::vector<int> a{1, 2, 3};
std::vector<int> b{std::move(a)};

This is equivalent to:

std::vector<int> a{1, 2, 3};
std::vector<int> b{static_cast<std::vector<int>&&>(a)};

Again, there's nothing special about the rvalue reference && that makes it "move" things, all the move semantics are in the std::vector constructor. The int type doesn't have any special move semantics, so it doesn't do that.

This makes sense. For a std::vector, moving the vector and zeroing the original is cheaper than a copy. For an int, zeroing the original is actually more expensive than just copying it--you have to copy the value anyway, so there is no point in doing extra work to throw away the original.

Dietrich Epp
  • 182,361
  • 34
  • 307
  • 387
  • IN the code snippet provided, if I try to access the values of vector a, what will the size of a be and what will the contents of a be? – arjun jawalkar Jun 06 '18 at 18:08
  • 1
    See the documentation for the `std::vector` constructor. "After the move, other is guaranteed to be empty()." http://en.cppreference.com/w/cpp/container/vector/vector – Dietrich Epp Jun 06 '18 at 18:15
  • @arjunjawalkar: I was unable to substantiate this claim using the C++ standard, there's a longer discussion here: https://stackoverflow.com/questions/17730689/is-a-moved-from-vector-always-empty In general, I would consider it a style error to use an object after moving from it, unless it is reinitialized somehow. – Dietrich Epp Jun 06 '18 at 19:43
2

But shouldn't it be as below?

No it should not.


Theory

1) std::move:

std::move produces an xvalue expression that identifies its argument t. It is exactly equivalent to a static_cast to an rvalue reference type.

2) Rvalue references:

Rvalue references can be used to extend the lifetimes of temporary objects (note, lvalue references to const can extend the lifetimes of temporary objects too, but they are not modifiable through them):

Conclusion: since a is not a temporary, your code is essentially equivalent to passing a as a reference.


Side note: in standard library

Unless otherwise specified, all standard library objects that have been moved from are placed in a valid but unspecified state.

AMA
  • 3,838
  • 13
  • 30