C++, take const lvalue and rvalue reference in a function - c++

I have a few methods that I need to give them ability to take variable by const lvalue (where it would be copied) and rvalue reference (for speed)
struct Object {
...
Object(Object&& o) { ... }
Object(const Object& o) { ... }
...
};
...
struct SomeClass {
...
Object arr[7];
void copy(int pos,const Object& o) { arr[pos] = o; }
void copy(int pos,Object&& o) { arr[pos] = o; }
...
};
So, two copy methods are COMPLETELY IDENTICAL in SomeClass. The only difference is that in one Object is passed as const, which will be copied, and in another Object is passed to be consumed for a quick copy as rvalue reference.
The code of these two methods is COMPLETELY IDENTICAL.
Now, it is not that tragic in the example above, however, I have methods that are a little larger, 9-15 lines or so. The workaround is, obviously, to copy them like it was done here, but it doesn't feel right.
How can I reuse the code of copy method?

Universal references and std::forward allow you to implement perfect forwarding. Here's the modified copy:
template <typename T>
void copy(int pos, T&& o) {arr[pos] = std::forward<T>(o);}
If you are worried about possible implicit conversions from other types to Object, you can also add a static_assert in the body of copy. If you pass an l-value Object to copy, T will be deduced to be Object&. std::forward<Object&> returns a reference. So, the copy assignment overload will be chosen. If you pass an r-value Object to copy, T will be deduced to be Object. std::forward<Object&> returns Object&&. Since std::forward<Object>(o) is an rvalue as well, the move assignment operator will get picked.

First, you are doing a copy assignment in both cases:
void copy(int pos,const Object& o) { arr[pos] = o; }
void copy(int pos,Object&& o) { arr[pos] = o; }
If it has a name, it's a lvalue. In the second function, o has a name, so it's a lvalue (despite being a rvalue reference). You want arr[pos] = std::move(o);.
The usual way to avoid having to write copy twice is to take o by value and move from it:
void copy(int pos, Object o) { arr[pos] = std::move(o); }
o will be copy constructed if you pass a lvalue, and then move-assigned into arr[pos]. If you pass a rvalue, o will be move constructed and then further move-assigned into the array. So you still avoid a copy in the rvalue case, but you pay for an extra move in both cases. If moves are cheap like they should be, it's not much extra overhead.
However, note that this does not work well with legacy types that do not support move semantics. In that case, this function will make a copy of what you passed and then copy-assign from that, while the two overloads taking references will only do one copy.

Related

I am pretty confused on the mental model for move semantics in C++ [duplicate]

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;

Do const and reference in function parameters cause unnecessary casts? [duplicate]

I have some pre-C++11 code in which I use const references to pass large parameters like vector's a lot. An example is as follows:
int hd(const vector<int>& a) {
return a[0];
}
I heard that with new C++11 features, you can pass the vector by value as follows without performance hits.
int hd(vector<int> a) {
return a[0];
}
For example, this answer says
C++11's move semantics make passing and returning by value much more attractive even for complex objects.
Is it true that the above two options are the same performance-wise?
If so, when is using const reference as in option 1 better than option 2? (i.e. why do we still need to use const references in C++11).
One reason I ask is that const references complicate deduction of template parameters, and it would be a lot easier to use pass-by-value only, if it is the same with const reference performance-wise.
The general rule of thumb for passing by value is when you would end up making a copy anyway. That is to say that rather than doing this:
void f(const std::vector<int>& x) {
std::vector<int> y(x);
// stuff
}
where you first pass a const-ref and then copy it, you should do this instead:
void f(std::vector<int> x) {
// work with x instead
}
This has been partially true in C++03, and has become more useful with move semantics, as the copy may be replaced by a move in the pass-by-val case when the function is called with an rvalue.
Otherwise, when all you want to do is read the data, passing by const reference is still the preferred, efficient way.
There is a big difference. You will get a copy of a vector's internal array unless it was about to die.
int hd(vector<int> a) {
//...
}
hd(func_returning_vector()); // internal array is "stolen" (move constructor is called)
vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8};
hd(v); // internal array is copied (copy constructor is called)
C++11 and the introduction of rvalue references changed the rules about returning objects like vectors - now you can do that (without worrying about a guaranteed copy). No basic rules about taking them as argument changed, though - you should still take them by const reference unless you actually need a real copy - take by value then.
C++11's move semantics make passing and returning by value much more attractive even for complex objects.
The sample you give, however, is a sample of pass by value
int hd(vector<int> a) {
So C++11 has no impact on this.
Even if you had correctly declared 'hd' to take an rvalue
int hd(vector<int>&& a) {
it may be cheaper than pass-by-value but performing a successful move (as opposed to a simple std::move which may have no effect at all) may be more expensive than a simple pass-by-reference. A new vector<int> must be constructed and it must take ownership of the contents of a. We don't have the old overhead of having to allocate a new array of elements and copy the values over, but we still need to transfer the data fields of vector.
More importantly, in the case of a successful move, a would be destroyed in this process:
std::vector<int> x;
x.push(1);
int n = hd(std::move(x));
std::cout << x.size() << '\n'; // not what it used to be
Consider the following full example:
struct Str {
char* m_ptr;
Str() : m_ptr(nullptr) {}
Str(const char* ptr) : m_ptr(strdup(ptr)) {}
Str(const Str& rhs) : m_ptr(strdup(rhs.m_ptr)) {}
Str(Str&& rhs) {
if (&rhs != this) {
m_ptr = rhs.m_ptr;
rhs.m_ptr = nullptr;
}
}
~Str() {
if (m_ptr) {
printf("dtor: freeing %p\n", m_ptr)
free(m_ptr);
m_ptr = nullptr;
}
}
};
void hd(Str&& str) {
printf("str.m_ptr = %p\n", str.m_ptr);
}
int main() {
Str a("hello world"); // duplicates 'hello world'.
Str b(a); // creates another copy
hd(std::move(b)); // transfers authority for b to function hd.
//hd(b); // compile error
printf("after hd, b.m_ptr = %p\n", b.m_ptr); // it's been moved.
}
As a general rule:
Pass by value for trivial objects,
Pass by value if the destination needs a mutable copy,
Pass by value if you always need to make a copy,
Pass by const reference for non-trivial objects where the viewer only needs to see the content/state but doesn't need it to be modifiable,
Move when the destination needs a mutable copy of a temporary/constructed value (e.g. std::move(std::string("a") + std::string("b"))).
Move when you require locality of the object state but want to retain existing values/data and release the current holder.
Remember that if you are not passing in an r-value, then passing by value would result in a full blown copy. So generally speaking, passing by value could lead to a performance hit.
Your example is flawed. C++11 does not give you a move with the code that you have, and a copy would be made.
However, you can get a move by declaring the function to take an rvalue reference, and then passing one:
int hd(vector<int>&& a) {
return a[0];
}
// ...
std::vector<int> a = ...
int x = hd(std::move(a));
That's assuming that you won't be using the variable a in your function again except to destroy it or to assign to it a new value. Here, std::move casts the value to an rvalue reference, allowing the move.
Const references allow temporaries to be silently created. You can pass in something that is appropriate for an implicit constructor, and a temporary will be created. The classic example is a char array being converted to const std::string& but with std::vector, a std::initializer_list can be converted.
So:
int hd(const std::vector<int>&); // Declaration of const reference function
int x = hd({1,2,3,4});
And of course, you can move the temporary in as well:
int hd(std::vector<int>&&); // Declaration of rvalue reference function
int x = hd({1,2,3,4});

Difference between std::move and assignment in C++ [duplicate]

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;

Spamming std::move is the way to go?

About std::move, here is what I can interpret, according to http://en.cppreference.com/w/cpp/utility/move :-
If I want to transfer ownership, I have to call std::move (or in rare case, std::forward).
Responsibility of std::move is calling operator=(A&& other).
The most essential step of the move operation is supposed to be implemented in operator=(A&&).
It is tricky to ensure that operator=(A&&) would be called. It need a special converter.
There are only two converters in the C++ world that can convert variables into xvalue (the &&) : std::move and std::forward.
Question
After adding many of std::move(std::unique_ptr) in my code, I start to worry that for such basic feature like transfer ownership, I have to heavily rely on the standard library (std::).
Do I really have to use std::move to transfer ownership?
Is spamming and hard-code calling std::move in many places of code-base a correct way to go for a high-standard program?
Should std::move be encapsulated?
They are actually a single question, but ask in different perspectives.
Edit
As request, here is my trial & error. It compiled ok.
I have no problem about the code, but I worry about its approach / pattern.
https://ideone.com/y8Pcgf
class T{
public: int value;
public: T(int a=1234){
value = a;
}
};
int main() {
std::unique_ptr<T> t1 = std::unique_ptr<T>(new T(1));
void* databaseNew=operator new [](sizeof(std::unique_ptr<T>));
std::unique_ptr<T>* t1ptr=static_cast<std::unique_ptr<T>*>(databaseNew);
new (t1ptr) std::unique_ptr<T>(std::move(t1));
return 0;
}
Rule of thumb:
If you're in a deduced x-value context, use std::forward:
template<class T>
void foo(T&& t) // T is deduced x-value, so we forward it
{
bar(std::forward<T>(t));
}
Otherwise use std::move
template<class T>
void foo1(std::vector<T> v) // although vector<T> is deduced, it's not an x-value
{
bar(std::move(v)); // so move it
}
template<class T>
void foo2(std::vector<T>&& v) // although vector<T> is deduced, it's not an x-value.
// In this case an r-value reference
{
bar(std::move(v)); // so move it
}
template<class T>
void foo3(std::vector<T>& v) // although vector<T> is deduced, it's not an x-value.
// In this case an l-value reference
{
bar(std::move(v)); // so move it
}
void foo4(std::vector<int> v) // complete type
{
bar(std::move(v)); // so move it
}
void foo5(std::vector<int> const & v) // const reference
{
bar(v); // not much point in moving it. std::move would cast it
// to std::vector<int> const&&, which although is detectable
// decays to std::vector<int> const&
}
which although is detectable... what?
It is permissible, if not necessarily advisable to write code like this:
#include <iostream>
struct X
{
void foo() const &
{
// do one thing...
std::cout << "one thing\n";
}
void foo() const &&
{
// do something else...
std::cout << "or another\n";
}
};
int main()
{
const X x;
x.foo();
std::move(x).foo();
}
const r-value references do exist, it's just that no-one uses them because there is no reasonable use-case.
The need to explicitly move, of which you complain, was actually done on purpose. Before unique_ptr, STL had a horrid construct called auto_ptr. It would move ownership impllicitly, and was borderline unusable unless you really really really knew what you were doing.
To make things more usable, in most cases C++ now requires you to explicitly state that you intend on moving ownership over a container, by using std::move.
In fact, std::move is little more than a cast to an rvalue reference.
There are cases where such an explicit specification is not necessary. For example, if the container from which you take ownership is already an rvalue (e.g. - a temporary object), then no case using std::move is necessary. For example, the following doesn't compile:
std::unique_ptr<int> a;
a = new int;
But the following does, without needing a move:
std::unique_ptr<int> a;
a = std::unique_ptr<int>(new int);
The reason this does not need a call to std::move, despite invoking the move operator, is that the object we move the ownership away from is already a temporary object (i.e. - an rvalue), so no cast is necessary.
Another example is if you call a function that returns a unique_ptr. You might have to call std::move inside the function to get it into the return value, but you do not need to call std::move on the function's return value to get it into the outside unique_ptr. It is already an rvalue, and therefor no cast is necessary.

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;