Search code examples
c++visual-studioqtrvalue-reference

Assigning rvalue reference to member variable


I am trying to write an efficient method to assign an Image (a QImage - Qt5.3) to a member variable of my class:

void ImageView::setImage(QImage&& image){
    std::cout << &image << std::endl;

    _image = image;
    //_image = std::move(image);

    std::cout << &_image << std::endl;

    _imageAssigned = true;
    updateResizedImage();
    update();
}

There are two lines of code that I could potentially use, the first one is _image = image; and the second one is _image = std::move(image);. Now I think the first line should be perfectly fine and should actually use the =operator overload of QImage that takes an rvalue reference since image is already an rvalue reference. The tooltip of Visual Studio, however, shows me that the normal =operator is used. If I use the second line instead, the tooltip shows the overload that uses the rvalue. Now my question is why that is the case. Ist the first line not sufficient? Calling move on a variable that is already an rvalue reference seems superflous to me.

I tried to test this myself by outputting the pointers (as can be seen in the code). Now, the pointers are different regardless of which line I use. This I find confusing. As it appears, my code is not working out the way I thought it would. Can anyone tell me what I did wrong?

Thank you for your help


Solution

  • An object with a name is an lvalue. The declaration as QImage&& indicates that only an rvalue can be bound to this reference but the reference itself is always an lvalue: it has a name. If you want to forward the rvalueness of an entity, you have to do so explicitly using std::move(). In case the rvalueness is deduced (i.e., you use a deduced template argument of the form T&& where T a template parameter) you'll forward the rvalueness conditionally using std::forward<T>(arg).

    The addresses of image and _image are, of course, different as they are different objects in the first place. If QImage contains an object with an address you could verify whether the object was moved using that address. For example if you used std::vector<T> instead of QImage you could use something like this to determine if the array was moved:

    void f(std::vector<T>&& v) {
        std::cout << (v.empty()? 0: v.data()) << '\n';
        std::vector<T> other;
        other = v; // will be copied
        std::cout << (other.empty()? 0: v.data()) << '\n';
        other = std::move(v); // will be moved
        std::cout << (other.empty()? 0: v.data()) << '\n';
    }