Move Semantics C++11 (Bjarne Stroustrup book, pg75) - c++

I'm trying to make me clear about move semantics. I'm following examples of the Bjarne Stroustrup book 4th edition and I'm really lost.
He says that copy of objects can be expensive when a lot of elements (in class vector) so move semantics is the solution.
Think something like:
Vector result = vector1 + vector2 + vector3;
Order may be wrong but it will do (vector2 + vector3) generating partial result result1, and result1 + vector1, generating result;
I overloaded operator+:
Vector operator+(const Vector &a,const Vector &b)
{
if(a.size()!=b.size()) {
throw length_error{"Length of vectors must match for summing"};
}
Vector result(a.size());
cout << "Intermediate result for sum created" << endl;
for(long unsigned int i=0; i<result.size();i++){
result[i] = a[i] + b[i];
}
return result;
}
I also created a move constructor:
Vector::Vector(Vector&& orig) noexcept
:elem{orig.elem},
sz{orig.sz}
{
cout << "Move constructor called" << endl;
orig.elem = nullptr; // We own the array now
orig.sz = 0;
}
So no copy operations are performed. But there are some things I don't understand. One is related to just c++ and the other to c++11.
So first:
As you can see, when operator+ exits Vector result should be destroyed. But not after the contents are copied to another instance of vector. What I called partial result1.
This never happens, the output of the program is like this:
New class vector created <-- Constructor of partial result 1
Intermediate result for sum created <-- Operator+ applied
New class vector created <-- Constructor of partial result 2 -> goes to result
Intermediate result for sum created <-- Operator+ applied
Class vector destroyed <-- I undenderstand that partial result 1 destroyed.
But I don't see the second partial result destroyed until the end of the program. Nor I see any copy operations (I have done operator= and copy constructor).
So I don't understand that. If the scope of the variable Vector result is inside operator+ the contents MUST be copied to another variable. That's not done. It seems that last result of the sum is just assigned to Vector result of the sum.
Second:
No move operations are performed. I cannot get move semantics to work here. I took a look to http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52745 and applied what's there but no move operations anyway.
Every result is right.
So clearly, there is something I'm doing wrong.
You can grab the whole code (with autotools config + eclipse) from here:
http://static.level2crm.com/cx11-learn-20140218.tar.bz2
Can someone explain what happens here?
Best regards,

First and foremost, there is no move-construction here. There is NRVO occurring (as per comments on your question) but if you want to testify of move-construction occurring, you should try to copy a temporary. Try re-implementing your operator as follows:
// Note that the first parameter is taken by value.
Vector operator+(Vector a, const Vector &b)
{
cout << "Intermediate result for sum created or moved from a" << endl;
// NOTE: Could be implemented as operator+= and written a += b.
if(a.size()!=b.size()) {
throw length_error{"Length of vectors must match for summing"};
}
for(long unsigned int i=0; i<a.size();i++){
a[i] += b[i];
}
// END NOTE
return a;
}
Note that your operator now requires a local "copy" as first parameter. On the first sum, since a Vector& will be provided as argument (the object has a name), the copy constructor will be called and create an object with a new buffer (what you are doing with your result local variable). Then, a temporary will be formed, so on the second call to your operator+, a Vector&& will be provided as first argument and the move-constructor will be called, effectively stealing the buffer of the temporary.
If you prevent constructor elision as per comments, you should be able to see some move constructors called.
EDIT: A more detailed explanation of why you won't have a move in your case. The short version is that C++ does not do magic :)
The aim of a move in the case of chained additions is to avoid repeatedly creatingthe buffers of your Vectors due to the creation of temporaries. Instead of losing the buffers to the destruction of the temporaries, the aim is to reuse the buffer of the temporary to store the result.
In your case, you're not even trying to copy the buffer of the Vector. You're explicitly creating a new buffer on this line:
Vector result(a.size());
You're saying "Please create a vector of the right size for the result", and doing it once for every addition. You had better say "Please steal the buffer of a" if you know that a will die soon. It is written:
Vector result(a);
But for this to work, a must refer to an object that will die soon, and this means a must be of type Vector&&. When this is done, result already contains the values of a, so all you have to do is add the values of the elements of b.
for(long unsigned int i=0; i<result.size();i++){
result[i] += b[i];
}
(Expressing + in terms of += is idiomatic)
So to testify of move construction, you should have a definition of your operator+ whose signature is:
Vector operator+(Vector&& a, const Vector &b) {
if(a.size()!=b.size()) {
throw length_error{"Length of vectors must match for summing"};
}
Vector result(a);
cout << "Intermediate result for sum moved from a" << endl;
for(long unsigned int i=0; i<result.size();i++){
result[i] += b[i];
}
return result;
}
But this won't work with the first addition, since it is not adding a temporary to another named object, but two named objects. You should have an overload of your operator+ that copes with lvalue references:
Vector operator+(const Vector& a, const Vector &b) {
if(a.size()!=b.size()) {
throw length_error{"Length of vectors must match for summing"};
}
Vector result(a); // In this case, this is a copy
cout << "Intermediate result for sum created" << endl;
for(long unsigned int i=0; i<result.size();i++){
result[i] += b[i];
}
return result;
}
Notice that both versions share the same text. Which brings to another idiomatic way of doing: letting the compiler decide of whether to do the move or the copy by requiring the left side of operator+ to be passed by value, requiring only one overload. (This is the version at the beginning of my answer.

Related

When move semantics required on practice (in case there is copy elision) [duplicate]

As far as I understand one of the purposes of adding move semantics is to optimize code by calling special constructor for copying "temporary" objects. For example, in this answer we see that it can be used to optimize such string a = x + y stuff. Because x+y is an rvalue expression, instead of deep copying we can copy only the pointer to the string and the size of the string. But as we know, modern compilers support return value optimization, so without using move semantics our code will not call the copy constructor at all.
To prove it I write this code:
#include <iostream>
struct stuff
{
int x;
stuff(int x_):x(x_){}
stuff(const stuff & g):x(g.x)
{
std::cout<<"copy"<<std::endl;
}
};
stuff operator+(const stuff& lhs,const stuff& rhs)
{
stuff g(lhs.x+rhs.x);
return g;
}
int main()
{
stuff a(5),b(7);
stuff c = a+b;
}
And after executing it in VC++2010 and g++ in optimize mode I'm getting empty output.
What kind of optimization is it, if without it my code still works faster? Could you explain what I'm understanding wrong?
Move semantics should not be thought as an optimization device, even if they can be used as such.
If you are going to want copies of objects (either function parameters or return values), then RVO and copy elision will do the job when they can. Move semantics can help, but are more powerful than that.
Move semantics are handy when you want to do something different whether the passed object is a temporary (it then binds to a rvalue reference) or a "standard" object with a name (a so called const lvalue). If you want for instance to steal the resources of a temporary object, then you want move semantics (example: you can steal the contents a std::unique_ptr points to).
Move semantics allow you to return non copyable objects from functions, which is not possible with the current standard. Also, non copyable objects can be put inside other objects, and those objects will automatically be movable if the contained objects are.
Non copyable objects are great, since they don't force you to implement an error-prone copy constructor. A lot of the time, copy semantics do not really make sense, but move semantics do (think about it).
This also enables you to use movable std::vector<T> classes even if T is non copyable. The std::unique_ptr class template is also a great tool when dealing with non copyable objects (eg. polymorphic objects).
After some digging I find this excellent example of optimization with rvalue references inStroustrup's FAQ .
Yes, swap function:
template<class T>
void swap(T& a, T& b) // "perfect swap" (almost)
{
T tmp = move(a); // could invalidate a
a = move(b); // could invalidate b
b = move(tmp); // could invalidate tmp
}
This will generate optimized code for any kind of types (assuming, that it have move constructor).
Edit: Also RVO can't optimize something like this(at least on my compiler):
stuff func(const stuff& st)
{
if(st.x>0)
{
stuff ret(2*st.x);
return ret;
}
else
{
stuff ret2(-2*st.x);
return ret2;
}
}
This function always calls copy constructor (checked with VC++). And if our class can be moved faster, than with move constructor we will have optimization.
Imagine your stuff was a class with heap allocated memory like a string, and that it had the notion of capacity. Give it a operator+= that will grow the capacity geometrically. In C++03 this might look like:
#include <iostream>
#include <algorithm>
struct stuff
{
int size;
int cap;
stuff(int size_):size(size_)
{
cap = size;
if (cap > 0)
std::cout <<"allocating " << cap <<std::endl;
}
stuff(const stuff & g):size(g.size), cap(g.cap)
{
if (cap > 0)
std::cout <<"allocating " << cap <<std::endl;
}
~stuff()
{
if (cap > 0)
std::cout << "deallocating " << cap << '\n';
}
stuff& operator+=(const stuff& y)
{
if (cap < size+y.size)
{
if (cap > 0)
std::cout << "deallocating " << cap << '\n';
cap = std::max(2*cap, size+y.size);
std::cout <<"allocating " << cap <<std::endl;
}
size += y.size;
return *this;
}
};
stuff operator+(const stuff& lhs,const stuff& rhs)
{
stuff g(lhs.size + rhs.size);
return g;
}
Also imagine you want to add more than just two stuff's at a time:
int main()
{
stuff a(11),b(9),c(7),d(5);
std::cout << "start addition\n\n";
stuff e = a+b+c+d;
std::cout << "\nend addition\n";
}
For me this prints out:
allocating 11
allocating 9
allocating 7
allocating 5
start addition
allocating 20
allocating 27
allocating 32
deallocating 27
deallocating 20
end addition
deallocating 32
deallocating 5
deallocating 7
deallocating 9
deallocating 11
I count 3 allocations and 2 deallocations to compute:
stuff e = a+b+c+d;
Now add move semantics:
stuff(stuff&& g):size(g.size), cap(g.cap)
{
g.cap = 0;
g.size = 0;
}
...
stuff operator+(stuff&& lhs,const stuff& rhs)
{
return std::move(lhs += rhs);
}
Running again I get:
allocating 11
allocating 9
allocating 7
allocating 5
start addition
allocating 20
deallocating 20
allocating 40
end addition
deallocating 40
deallocating 5
deallocating 7
deallocating 9
deallocating 11
I'm now down to 2 allocations and 1 deallocations. That translates to faster code.
There are many places some of which are mentioned in other answers.
One big one is that when resizing a std::vector it will move move-aware objects from the old memory location to the new one rather than copy and destroy the original.
Additionally rvalue references allow the concept of movable types, this is a semantic difference and not just an optimization. unique_ptr wasn't possible in C++03 which is why we had the abomination of auto_ptr.
Just because this particular case is already covered by an existing optimization does not mean that other cases don't exist where r-value references are helpful.
Move construction allows optimization even when the temporary is returned from a function which cannot be inlined (perhaps it's a virtual call, or through a function pointer).
Your posted example only takes const lvalue references and so explicitly cannot have move semantics applied to it, as there is not a single rvalue reference in there. How can move semantics make your code faster when you implemented a type without rvalue references?
In addition, your code is already covered by RVO and NRVO. Move semantics apply to far, far more situations than those two do.
This line calls the first constructor.
stuff a(5),b(7);
Plus operator is called using explicit common lvalue references.
stuff c = a + b;
Inside operator overload method, you have no copy constructor called.
Again, the first constructor is called only.
stuff g(lhs.x+rhs.x);
assigment is made with RVO, so no copy is need. NO copy from returned object to 'c' is need.
stuff c = a+b;
Due no std::cout reference, compiler take care about your c value is never used. Then, whole program is stripped out, resulting in a empty program.
Another good example I can think of. Imagine that you're implementing a matrix library and write an algorithm which takes two matrices and outputs another one:
Matrix MyAlgorithm(Matrix U, Matrix V)
{
Transform(U); //doesn't matter what this actually does, but it modifies U
Transform(V);
return U*V;
}
Note that you can't pass U and V by const reference, because the algorithm tweaks them. You could theoretically pass them by reference, but this would look gross and leave U and V in some intermediate state (since you call Transform(U)), which may not make any sense to the caller, or just not make any mathematical sense at all, since it's just one of the internal algorithm transformations. The code looks much cleaner if you just pass them by value and use move semantics if you are not going to use U and V after calling this function:
Matrix u, v;
...
Matrix w = MyAlgorithm(u, v); //slow, but will preserve u and v
Matrix w = MyAlgorithm(move(u), move(v)); //fast, but will nullify u and v
Matrix w = MyAlgorithm(u, move(v)); //and you can even do this if you need one but not the other

Operator overloading C++ for operator+ and operator=

I've been scratching my head all day new to operator overloading and my operator+ function computes the data correctly, but I need to pass the data of temp class to operator= to assign it to a separate instance of my class and returning temp does not work (I imagine the data is being destroyed on exit?)
the whole idea is from main x = y + z is called to add the data of two vectors from y and z and asign it to x and I get the computation of y + z correctly, but passing it to x I've hit a brick wall what is wrong? or does anyone have idea?
This is piece my code from my class
VecXd& operator=(const VecXd& rhs)
{
VecXd<V> temp;
temp.dimension = rhs.dimension;
cout << "operator= check dimension is..." << temp.dimension << endl;
for(int i = 0; i < rhs.dimension; i++) //Passing data to x?
{
cout << "test" << endl;
temp.vecArr[i] = rhs.vecArr[i];
cout << temp.vecArr[i] << " our new value" << endl;
}
}
friend VecXd& operator+(VecXd& lhs, VecXd& rhs){
VecXd<V> temp;
cout << lhs.dimension << "-lhs d-" << rhs.dimension << "-rhs d-" << endl; //works
if(lhs.dimension == rhs.dimension) //dimension level check
{
temp.vecArr = new V[lhs.dimension];
for(int i = 0; i < lhs.dimension; i++)
{
temp.vecArr[i] = lhs.vecArr[i] + rhs.vecArr[i];
cout << temp.vecArr[i] << " our new value" << endl;
}
//return *temp.vecArr;
return temp; //***? how to pass data?
}
else{
cout << "Dimensions do not match!!! Error!" << endl;
}
}
any idea? don't be to harsh... haha..... :l
Your assignment operator is bogus: the operation the assignment is supposed to do is to make the object pointed to by this the same as the object on the right hand side. Your assignment operator creates a temporary object and sets this object up. However, it goes away when exiting the assignment operator. Also, you declared your assignment operator to return a reference which conventionally returns a reference to *this but there is no return
statement.
Unless I have a very good reason to do it differently, I implement my assignment operator in terms of the copy constructor, the destructor, and a swap() function:
VecXd& VecXd::operator=(VecXd rhs)
{
this->swap(rhs);
return *this;
}
The copy constructor is called to create the argument to function, nicely copying the object. Then the newly created copy is exchanged with the content of the object being assigned to and, after returning *this the original content is released by the destructor of the temporary object created for rhs. All what is required is a relatively function swap():
void VecXd::swap(VecXd& other)
{
std::swap(this->dimension, other.dimension);
std::swap(this->vecArr, other.vecArr);
}
The swap() function assumes that the two members can be swapped, of course. Since I haven't seen your declaration of VecXd I can't tell whether this would work but it should generally work.
I haven't really looked at your addition operator.
This Caltech C++ Operator Overloading Page should have everything you need and a relatively clear explanation of the logic involved. It is not by any means required that you follow the rules and guidelines laid out there, but they work well in the general case.
In the specific case of the arithmetic operators, the operation is often defined in terms of the += operator, as noted in the comment on your original post by chris. This means that you typically pass in the right and left arguments, make a copy of lhs, and find the result by using lhs_copy += rhs; it's easier to avoid code duplication with this in mind; you'll only be creating the addition logic once in += and then calling it in +.
The result you return cannot be a reference - nothing created in the function will persist, but neither the lhs or rhs arguments should be changed. Instead, you simply return the duplicate lhs you incremented as an instance - in your case the function signature is:
const VecXd operator+(const VecXd& lhs, const VecXd& rhs).
Your input can and should be const since neither item will be changed in the function, and the Caltech page recommends the return type be a const instance to disallow certain odd operations, which again is good practice in many cases.

C++ strange behaviour with function call by value

I have an object which is a class interface to the matrix struct found in the GNU Scientific Library
typedef double real_t;
typedef unsigned short index_t;
class matrix
{
gsl_matrix* m;
public:
matrix(index_t rows, index_t columns, real_t val);
}
matrix::matrix(index_t rows, index_t columns, real_t val)
{
m=gsl_matrix_alloc(rows,columns);
gsl_matrix_set_all(m, val);
return;
}
index_t matrix::rows(void)
{
return m->size1;
}
index_t matrix::columns(void)
{
return m->size2;
}
the problem is that if I use a function taking the matrix object by value like this one:
void test_function(const matrix m){};
and use it in a program like this one
int main()
{
matrix m(4,4,1);
cout << m.rows() << '\t' << m.columns() << endl;
test_function(m);
cout << m.rows() << '\t' << m.columns() << endl;
}
I surprisingly obtain that the number of rows of the matrix object m is modified by the function test_function to garbage value, even if I put the keyword const before the argument and the call is made by value.
But the strangest thing is that if I use a function that makes use of call by reference like this one:
void test_function(const matrix &m){};
nothing happens and everything seems to be all right.
As far as I know, call by value shouldn't be able to modify the argument of the function,
especially if the function does nothing as in this case and especially if I explicitly use the keyword const before the argument name in the function prototype...
Any help would be greatly appreciated.
EDIT:
I also have defined the copy constructor for the matrix class as
matrix& matrix::operator= (const matrix& src)
{
gsl_matrix_memcpy(m,src.m);
return *this;
}
which does a complete copy (I guess) of the gsl_matrix struct
EDIT:
Ok, I think I've finally understood: the call by value function creates a shallow copy object that just contains the pointer to the real object, when test_function terminates all local variables are destroyed, so the destructor of the matrix class (which is defined but omitted here for the sake of brevity) is called, but in this way the object in the main (to which the local m points to) is destroyed together with the local variable.. Anyway I solved the problem defining a proper copy constructor that performs a complete (deep) copy of the object and then using call by reference which should be better for heavy computation. Thanks a lot to everybody for your help!
because the default copy ctor just makes a shallow copy, that is, it just copies the value of pointer m, instead of allocate a new one.
When you pass an argument by value, compiler calls the one-argument copy constructor to create the value in the function. If you do not provide a copy constructor, compiler generates one for you.
In the example above, compiler generated copy constructor makes shallow copy of the inner matrix pointer. When the newly generated matrix in the function goes out of scope, the shallow copied pointer gets deleted also. My guess is this is the reason.
You could check this by providing a copy constructor which does not copy the gsl_matrix pointer.

What optimization does move semantics provide if we already have RVO?

As far as I understand one of the purposes of adding move semantics is to optimize code by calling special constructor for copying "temporary" objects. For example, in this answer we see that it can be used to optimize such string a = x + y stuff. Because x+y is an rvalue expression, instead of deep copying we can copy only the pointer to the string and the size of the string. But as we know, modern compilers support return value optimization, so without using move semantics our code will not call the copy constructor at all.
To prove it I write this code:
#include <iostream>
struct stuff
{
int x;
stuff(int x_):x(x_){}
stuff(const stuff & g):x(g.x)
{
std::cout<<"copy"<<std::endl;
}
};
stuff operator+(const stuff& lhs,const stuff& rhs)
{
stuff g(lhs.x+rhs.x);
return g;
}
int main()
{
stuff a(5),b(7);
stuff c = a+b;
}
And after executing it in VC++2010 and g++ in optimize mode I'm getting empty output.
What kind of optimization is it, if without it my code still works faster? Could you explain what I'm understanding wrong?
Move semantics should not be thought as an optimization device, even if they can be used as such.
If you are going to want copies of objects (either function parameters or return values), then RVO and copy elision will do the job when they can. Move semantics can help, but are more powerful than that.
Move semantics are handy when you want to do something different whether the passed object is a temporary (it then binds to a rvalue reference) or a "standard" object with a name (a so called const lvalue). If you want for instance to steal the resources of a temporary object, then you want move semantics (example: you can steal the contents a std::unique_ptr points to).
Move semantics allow you to return non copyable objects from functions, which is not possible with the current standard. Also, non copyable objects can be put inside other objects, and those objects will automatically be movable if the contained objects are.
Non copyable objects are great, since they don't force you to implement an error-prone copy constructor. A lot of the time, copy semantics do not really make sense, but move semantics do (think about it).
This also enables you to use movable std::vector<T> classes even if T is non copyable. The std::unique_ptr class template is also a great tool when dealing with non copyable objects (eg. polymorphic objects).
After some digging I find this excellent example of optimization with rvalue references inStroustrup's FAQ .
Yes, swap function:
template<class T>
void swap(T& a, T& b) // "perfect swap" (almost)
{
T tmp = move(a); // could invalidate a
a = move(b); // could invalidate b
b = move(tmp); // could invalidate tmp
}
This will generate optimized code for any kind of types (assuming, that it have move constructor).
Edit: Also RVO can't optimize something like this(at least on my compiler):
stuff func(const stuff& st)
{
if(st.x>0)
{
stuff ret(2*st.x);
return ret;
}
else
{
stuff ret2(-2*st.x);
return ret2;
}
}
This function always calls copy constructor (checked with VC++). And if our class can be moved faster, than with move constructor we will have optimization.
Imagine your stuff was a class with heap allocated memory like a string, and that it had the notion of capacity. Give it a operator+= that will grow the capacity geometrically. In C++03 this might look like:
#include <iostream>
#include <algorithm>
struct stuff
{
int size;
int cap;
stuff(int size_):size(size_)
{
cap = size;
if (cap > 0)
std::cout <<"allocating " << cap <<std::endl;
}
stuff(const stuff & g):size(g.size), cap(g.cap)
{
if (cap > 0)
std::cout <<"allocating " << cap <<std::endl;
}
~stuff()
{
if (cap > 0)
std::cout << "deallocating " << cap << '\n';
}
stuff& operator+=(const stuff& y)
{
if (cap < size+y.size)
{
if (cap > 0)
std::cout << "deallocating " << cap << '\n';
cap = std::max(2*cap, size+y.size);
std::cout <<"allocating " << cap <<std::endl;
}
size += y.size;
return *this;
}
};
stuff operator+(const stuff& lhs,const stuff& rhs)
{
stuff g(lhs.size + rhs.size);
return g;
}
Also imagine you want to add more than just two stuff's at a time:
int main()
{
stuff a(11),b(9),c(7),d(5);
std::cout << "start addition\n\n";
stuff e = a+b+c+d;
std::cout << "\nend addition\n";
}
For me this prints out:
allocating 11
allocating 9
allocating 7
allocating 5
start addition
allocating 20
allocating 27
allocating 32
deallocating 27
deallocating 20
end addition
deallocating 32
deallocating 5
deallocating 7
deallocating 9
deallocating 11
I count 3 allocations and 2 deallocations to compute:
stuff e = a+b+c+d;
Now add move semantics:
stuff(stuff&& g):size(g.size), cap(g.cap)
{
g.cap = 0;
g.size = 0;
}
...
stuff operator+(stuff&& lhs,const stuff& rhs)
{
return std::move(lhs += rhs);
}
Running again I get:
allocating 11
allocating 9
allocating 7
allocating 5
start addition
allocating 20
deallocating 20
allocating 40
end addition
deallocating 40
deallocating 5
deallocating 7
deallocating 9
deallocating 11
I'm now down to 2 allocations and 1 deallocations. That translates to faster code.
There are many places some of which are mentioned in other answers.
One big one is that when resizing a std::vector it will move move-aware objects from the old memory location to the new one rather than copy and destroy the original.
Additionally rvalue references allow the concept of movable types, this is a semantic difference and not just an optimization. unique_ptr wasn't possible in C++03 which is why we had the abomination of auto_ptr.
Just because this particular case is already covered by an existing optimization does not mean that other cases don't exist where r-value references are helpful.
Move construction allows optimization even when the temporary is returned from a function which cannot be inlined (perhaps it's a virtual call, or through a function pointer).
Your posted example only takes const lvalue references and so explicitly cannot have move semantics applied to it, as there is not a single rvalue reference in there. How can move semantics make your code faster when you implemented a type without rvalue references?
In addition, your code is already covered by RVO and NRVO. Move semantics apply to far, far more situations than those two do.
This line calls the first constructor.
stuff a(5),b(7);
Plus operator is called using explicit common lvalue references.
stuff c = a + b;
Inside operator overload method, you have no copy constructor called.
Again, the first constructor is called only.
stuff g(lhs.x+rhs.x);
assigment is made with RVO, so no copy is need. NO copy from returned object to 'c' is need.
stuff c = a+b;
Due no std::cout reference, compiler take care about your c value is never used. Then, whole program is stripped out, resulting in a empty program.
Another good example I can think of. Imagine that you're implementing a matrix library and write an algorithm which takes two matrices and outputs another one:
Matrix MyAlgorithm(Matrix U, Matrix V)
{
Transform(U); //doesn't matter what this actually does, but it modifies U
Transform(V);
return U*V;
}
Note that you can't pass U and V by const reference, because the algorithm tweaks them. You could theoretically pass them by reference, but this would look gross and leave U and V in some intermediate state (since you call Transform(U)), which may not make any sense to the caller, or just not make any mathematical sense at all, since it's just one of the internal algorithm transformations. The code looks much cleaner if you just pass them by value and use move semantics if you are not going to use U and V after calling this function:
Matrix u, v;
...
Matrix w = MyAlgorithm(u, v); //slow, but will preserve u and v
Matrix w = MyAlgorithm(move(u), move(v)); //fast, but will nullify u and v
Matrix w = MyAlgorithm(u, move(v)); //and you can even do this if you need one but not the other

What is std::move(), and when should it be used?

What is it?
What does it do?
When should it be used?
Good links are appreciated.
1. "What is it?"
While std::move() is technically a function - I would say it isn't really a function. It's sort of a converter between ways the compiler considers an expression's value.
2. "What does it do?"
The first thing to note is that std::move() doesn't actually move anything. It changes an expression from being an lvalue (such as a named variable) to being an xvalue. An xvalue tells the compiler:
You can plunder me, move anything I'm holding and use it elsewhere (since I'm going to be destroyed soon anyway)".
in other words, when you use std::move(x), you're allowing the compiler to cannibalize x. Thus if x has, say, its own buffer in memory - after std::move()ing the compiler can have another object own it instead.
You can also move from a prvalue (such as a temporary you're passing around), but this is rarely useful.
3. "When should it be used?"
Another way to ask this question is "What would I cannibalize an existing object's resources for?" well, if you're writing application code, you would probably not be messing around a lot with temporary objects created by the compiler. So mainly you would do this in places like constructors, operator methods, standard-library-algorithm-like functions etc. where objects get created and destroyed automagically a lot. Of course, that's just a rule of thumb.
A typical use is 'moving' resources from one object to another instead of copying. #Guillaume links to this page which has a straightforward short example: swapping two objects with less copying.
template <class T>
swap(T& a, T& b) {
T tmp(a); // we now have two copies of a
a = b; // we now have two copies of b (+ discarded a copy of a)
b = tmp; // we now have two copies of tmp (+ discarded a copy of b)
}
using move allows you to swap the resources instead of copying them around:
template <class T>
swap(T& a, T& b) {
T tmp(std::move(a));
a = std::move(b);
b = std::move(tmp);
}
Think of what happens when T is, say, vector<int> of size n. In the first version you read and write 3*n elements, in the second version you basically read and write just the 3 pointers to the vectors' buffers, plus the 3 buffers' sizes. Of course, class T needs to know how to do the moving; your class should have a move-assignment operator and a move-constructor for class T for this to work.
Wikipedia Page on C++11 R-value references and move constructors
In C++11, in addition to copy constructors, objects can have move constructors.
(And in addition to copy assignment operators, they have move assignment operators.)
The move constructor is used instead of the copy constructor, if the object has type "rvalue-reference" (Type &&).
std::move() is a cast that produces an rvalue-reference to an object, to enable moving from it.
It's a new C++ way to avoid copies. For example, using a move constructor, a std::vector could just copy its internal pointer to data to the new object, leaving the moved object in an moved from state, therefore not copying all the data. This would be C++-valid.
Try googling for move semantics, rvalue, perfect forwarding.
You can use move when you need to "transfer" the content of an object somewhere else, without doing a copy (i.e. the content is not duplicated, that's why it could be used on some non-copyable objects, like a unique_ptr). It's also possible for an object to take the content of a temporary object without doing a copy (and save a lot of time), with std::move.
This link really helped me out :
http://thbecker.net/articles/rvalue_references/section_01.html
I'm sorry if my answer is coming too late, but I was also looking for a good link for the std::move, and I found the links above a little bit "austere".
This puts the emphasis on r-value reference, in which context you should use them, and I think it's more detailed, that's why I wanted to share this link here.
Q: What is std::move?
A: std::move() is a function from the C++ Standard Library for casting to a rvalue reference.
Simplisticly std::move(t) is equivalent to:
static_cast<T&&>(t);
An rvalue is a temporary that does not persist beyond the expression that defines it, such as an intermediate function result which is never stored in a variable.
int a = 3; // 3 is a rvalue, does not exist after expression is evaluated
int b = a; // a is a lvalue, keeps existing after expression is evaluated
An implementation for std::move() is given in N2027: "A Brief Introduction to Rvalue References" as follows:
template <class T>
typename remove_reference<T>::type&&
std::move(T&& a)
{
return a;
}
As you can see, std::move returns T&& no matter if called with a value (T), reference type (T&), or rvalue reference (T&&).
Q: What does it do?
A: As a cast, it does not do anything during runtime. It is only relevant at compile time to tell the compiler that you would like to continue considering the reference as an rvalue.
foo(3 * 5); // obviously, you are calling foo with a temporary (rvalue)
int a = 3 * 5;
foo(a); // how to tell the compiler to treat `a` as an rvalue?
foo(std::move(a)); // will call `foo(int&& a)` rather than `foo(int a)` or `foo(int& a)`
What it does not do:
Make a copy of the argument
Call the copy constructor
Change the argument object
Q: When should it be used?
A: You should use std::move if you want to call functions that support move semantics with an argument which is not an rvalue (temporary expression).
This begs the following follow-up questions for me:
What is move semantics? Move semantics in contrast to copy semantics is a programming technique in which the members of an object are initialized by 'taking over' instead of copying another object's members. Such 'take over' makes only sense with pointers and resource handles, which can be cheaply transferred by copying the pointer or integer handle rather than the underlying data.
What kind of classes and objects support move semantics? It is up to you as a developer to implement move semantics in your own classes if these would benefit from transferring their members instead of copying them. Once you implement move semantics, you will directly benefit from work from many library programmers who have added support for handling classes with move semantics efficiently.
Why can't the compiler figure it out on its own? The compiler cannot just call another overload of a function unless you say so. You must help the compiler choose whether the regular or move version of the function should be called.
In which situations would I want to tell the compiler that it should treat a variable as an rvalue? This will most likely happen in template or library functions, where you know that an intermediate result could be salvaged (rather than allocating a new instance).
std::move itself doesn't really do much. I thought that it called the moved constructor for an object, but it really just performs a type cast (casting an lvalue variable to an rvalue so that the said variable can be passed as an argument to a move constructor or assignment operator).
So std::move is just used as a precursor to using move semantics. Move semantics is essentially an efficient way for dealing with temporary objects.
Consider Object A = B + (C + (D + (E + F)));
This is nice looking code, but E + F produces a temporary object. Then D + temp produces another temporary object and so on. In each normal "+" operator of a class, deep copies occur.
For example
Object Object::operator+ (const Object& rhs) {
Object temp (*this);
// logic for adding
return temp;
}
The creation of the temporary object in this function is useless - these temporary objects will be deleted at the end of the line anyway as they go out of scope.
We can rather use move semantics to "plunder" the temporary objects and do something like
Object& Object::operator+ (Object&& rhs) {
// logic to modify rhs directly
return rhs;
}
This avoids needless deep copies being made. With reference to the example, the only part where deep copying occurs is now E + F. The rest uses move semantics. The move constructor or assignment operator also needs to be implemented to assign the result to A.
"What is it?" and "What does it do?" has been explained above.
I will give a example of "when it should be used".
For example, we have a class with lots of resource like big array in it.
class ResHeavy{ // ResHeavy means heavy resource
public:
ResHeavy(int len=10):_upInt(new int[len]),_len(len){
cout<<"default ctor"<<endl;
}
ResHeavy(const ResHeavy& rhs):_upInt(new int[rhs._len]),_len(rhs._len){
cout<<"copy ctor"<<endl;
}
ResHeavy& operator=(const ResHeavy& rhs){
_upInt.reset(new int[rhs._len]);
_len = rhs._len;
cout<<"operator= ctor"<<endl;
}
ResHeavy(ResHeavy&& rhs){
_upInt = std::move(rhs._upInt);
_len = rhs._len;
rhs._len = 0;
cout<<"move ctor"<<endl;
}
// check array valid
bool is_up_valid(){
return _upInt != nullptr;
}
private:
std::unique_ptr<int[]> _upInt; // heavy array resource
int _len; // length of int array
};
Test code:
void test_std_move2(){
ResHeavy rh; // only one int[]
// operator rh
// after some operator of rh, it becomes no-use
// transform it to other object
ResHeavy rh2 = std::move(rh); // rh becomes invalid
// show rh, rh2 it valid
if(rh.is_up_valid())
cout<<"rh valid"<<endl;
else
cout<<"rh invalid"<<endl;
if(rh2.is_up_valid())
cout<<"rh2 valid"<<endl;
else
cout<<"rh2 invalid"<<endl;
// new ResHeavy object, created by copy ctor
ResHeavy rh3(rh2); // two copy of int[]
if(rh3.is_up_valid())
cout<<"rh3 valid"<<endl;
else
cout<<"rh3 invalid"<<endl;
}
output as below:
default ctor
move ctor
rh invalid
rh2 valid
copy ctor
rh3 valid
We can see that std::move with move constructor makes transform resource easily.
Where else is std::move useful?
std::move can also be useful when sorting an array of elements. Many sorting algorithms (such as selection sort and bubble sort) work by swapping pairs of elements. Previously, we’ve had to resort to copy-semantics to do the swapping. Now we can use move semantics, which is more efficient.
It can also be useful if we want to move the contents managed by one smart pointer to another.
Cited:
https://www.learncpp.com/cpp-tutorial/15-4-stdmove/
std::move itself does nothing rather than a static_cast. According to cppreference.com
It is exactly equivalent to a static_cast to an rvalue reference type.
Thus, it depends on the type of the variable you assign to after the move, if the type has constructors or assign operators that takes a rvalue parameter, it may or may not steal the content of the original variable, so, it may leave the original variable to be in an unspecified state:
Unless otherwise specified, all standard library objects that have been moved from being placed in a valid but unspecified state.
Because there is no special move constructor or move assign operator for built-in literal types such as integers and raw pointers, so, it will be just a simple copy for these types.
Here is a full example, using std::move for a (simple) custom vector
Expected output:
c: [10][11]
copy ctor called
copy of c: [10][11]
move ctor called
moved c: [10][11]
Compile as:
g++ -std=c++2a -O2 -Wall -pedantic foo.cpp
Code:
#include <iostream>
#include <algorithm>
template<class T> class MyVector {
private:
T *data;
size_t maxlen;
size_t currlen;
public:
MyVector<T> () : data (nullptr), maxlen(0), currlen(0) { }
MyVector<T> (int maxlen) : data (new T [maxlen]), maxlen(maxlen), currlen(0) { }
MyVector<T> (const MyVector& o) {
std::cout << "copy ctor called" << std::endl;
data = new T [o.maxlen];
maxlen = o.maxlen;
currlen = o.currlen;
std::copy(o.data, o.data + o.maxlen, data);
}
MyVector<T> (const MyVector<T>&& o) {
std::cout << "move ctor called" << std::endl;
data = o.data;
maxlen = o.maxlen;
currlen = o.currlen;
}
void push_back (const T& i) {
if (currlen >= maxlen) {
maxlen *= 2;
auto newdata = new T [maxlen];
std::copy(data, data + currlen, newdata);
if (data) {
delete[] data;
}
data = newdata;
}
data[currlen++] = i;
}
friend std::ostream& operator<<(std::ostream &os, const MyVector<T>& o) {
auto s = o.data;
auto e = o.data + o.currlen;;
while (s < e) {
os << "[" << *s << "]";
s++;
}
return os;
}
};
int main() {
auto c = new MyVector<int>(1);
c->push_back(10);
c->push_back(11);
std::cout << "c: " << *c << std::endl;
auto d = *c;
std::cout << "copy of c: " << d << std::endl;
auto e = std::move(*c);
delete c;
std::cout << "moved c: " << e << std::endl;
}
std::move simply casts a variable to an rvalue reference. This rvalue reference is notated with &&. Let's say you have a class Foo and you instantiate an object like this
Foo foo = Foo();
If you then write
Foo foo2 = std::move(foo);
that's the same thing as If I wrote
Foo foo2 = (Foo&&) foo;
std::move replaces this cast to an rvalue reference.
The reason why you would want to write either of the previous 2 lines of code
is that if you write
Foo foo2 = foo;
The copy constructor will be called.
Let's say Foo instances have a pointer to some data on the heap which they own.
In Foo's destructor that data on the heap gets deleted.
If you want to distinghuish between copying the data from the heap and taking ownership of that data, you can write a constructor which takes in const Foo& and that constructor can perform the deep copy. Then you can write a constructor which takes in an rvalue reference (Foo&&) and this constructor can simply rewire the pointers.
This constructor which takes in Foo&& will be called when you write
Foo foo2 = std::move(foo);
and when you write
Foo foo2 = (Foo&&) foo;