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
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';
}