Search code examples
c++c++11movemove-semantics

Why move on const objects work?


I have a simple code :

const std::vector<int> data = {1,2,3};
std::vector<int> data_moved=std::move(data);
for(auto& i:data)
    cout<<i;//output is 123

It compiles without any errors or warning !!

and It seems the data still has the values in it !

moving a const value doesn't seems correct because we can not modify const objects So how does that code compiles ?!


Solution

  • You're not moving anything.

    std::move is really poorly named: it doesn't force a move; it just returns an rvalue. It's up to the compiler to decide which constructor of std::vector<int> to invoke, and that's what determines whether you get a move.

    If the container can't be moved because the target's move constructor isn't a match, then the copy constructor will be used instead, through basic overload rules.

    #include <iostream>
    
    struct T
    {
        T() = default;
        T(const T&) { std::cout << "copy ctor\n"; }
        T(T&&)      { std::cout << "move ctor\n"; }
    };
    
    int main()
    {
        T a;
        T b = std::move(a);   // "move ctor"
    
        const T c;
        T d = std::move(c);   // "copy ctor" - `const T&&` only matches copy ctor
    
    
    
        // (shut up GCC)
        (void) b;
        (void) d;
    }
    

    (live demo)

    It's designed this way (const T&& being able to bind to const T&) at least in part because moving is intended to be best-effort, exactly so that you don't have to fight with compiler errors in cases like this.