0

(Wasn't sure about the title of my post, apologies for the poor title). I've implemented the following piece of code:

#include <iostream>
#include <algorithm>

using namespace std;

class MyIntVector {
public:
    MyIntVector() {
        m_size = 10;
        m_mem = new int[m_size];
        for(auto i = 0; i < size(); ++i)
            m_mem[i] = 0;
    }
    MyIntVector(int size) {
        m_size = size;
        m_mem = new int[m_size];
    }
    MyIntVector(const MyIntVector& v) {
        m_mem = new int[v.size()];
        m_size = v.size();
        for(auto i = 0; i < v.size(); ++i)
            m_mem[i] = v[i];
    }
    MyIntVector(MyIntVector&& v) {
        cout << "Calling move constructor" << std::endl;
        m_size = v.size();
        m_mem = v.m_mem;
        v.m_mem = nullptr;
        delete [] v.m_mem;
    }
    int size() const {return m_size;}
    int& operator[](int i) { return m_mem[i];}
    int operator[](int i) const { return m_mem[i];}

    friend ostream& operator<<(ostream& os, const MyIntVector& v);

protected:
    int * getMemPtr() {return m_mem;}
private:
    int m_size;
    int *m_mem;
};

ostream &operator<<(ostream &os, const MyIntVector &v) {
    for (auto i = 0; i < v.size(); ++i)
        os << v[i] << " ";
    return os;
}

void linear_init(MyIntVector& v) {
    for(auto i = 0; i < v.size(); ++i)
        v[i] = i + 1;
}

int main(int argc, char** argv) {
    MyIntVector&& my_v_2 = MyIntVector(20); //binding R-value to R-value reference
    MyIntVector my_v_3(my_v_2);

    return 0;
}

In the main specifically I'm initializing an r-value reference, and later I'm using it to initialize another object. I was expecting however the move constructor to be called, but the copy constructor is called instead, can anyone explain me why?

(It is just some test code to understand move semantics and r-value references).

To be more specific I'd like to have a reference (in the documentation) that explains why the move constructor isn't called.

user8469759
  • 2,522
  • 6
  • 26
  • 50
  • 2
    A named r-value-reference is actually a l-value. You still need to move it in. Isn't C++ great? – Mike Vine Mar 01 '19 at 11:47
  • Ok, you got me confused xD. But I've noticed that if I do `MyIntVector my_v_3(std::move(my_v_2));` then the move constructor is called. – user8469759 Mar 01 '19 at 11:49
  • @MikeVine, can I have a reference for your statement? (In the official documentation). – user8469759 Mar 01 '19 at 11:53
  • It's simple, a `move` is not a moved object, it's just prepared to be moved, but as soon as you name it, it stops being prepared to be moved. – Matthieu Brucher Mar 01 '19 at 11:54
  • @MikeVine But at this point what could the point of initializing an r-value reference in the way I did? – user8469759 Mar 01 '19 at 12:02
  • "rvalue reference" means it binds to an rvalue, not that it is an rvalue – M.M Mar 01 '19 at 12:37
  • @M.M what do you pass as argument in a move constructor like `Object(T&& arg)`? Isn't it an r-value reference? – user8469759 Mar 01 '19 at 12:39
  • you pass an rvalue, because an rvalue reference binds to rvalues. (Also note that if `T` is a template parameter then that is not an rvalue reference, it's a forwarding reference, they have similar syntax but different behaviour) – M.M Mar 01 '19 at 12:42

1 Answers1

4

Simply put - everything that has a name is lvalue. And so, named rvalue reference, in your case my_v_2 is an lvalue. And when using lvalue move constructor is not called. To make it work you have to move it:

MyIntVector my_v_3(std::move(my_v_2));
bartop
  • 9,971
  • 1
  • 23
  • 54
  • Can I have a reference for the statement "A named r-value-reference is actually an l-value"? I have this page "https://en.cppreference.com/w/cpp/language/value_category" but I can't actually spot anything. – user8469759 Mar 01 '19 at 11:51
  • 1
    Found it... it was the very first point in the lvalue section: *The following expressions are lvalue expressions: the name of a variable, a function, a template parameter object (since C++20), or a data member, regardless of type, such as std::cin or std::endl. **Even if the variable's type is rvalue reference, the expression consisting of its name is an lvalue expression**;* – user8469759 Mar 01 '19 at 11:59