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;
Related
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;
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});
I was reading C++11 Faq and came across this code. I have a better understanding of C++ coding, but I'm still not able to understand the below code.
template<class T>
class Handle {
T* p;
public:
Handle(T* pp) : p{pp} {}
~Handle() { delete p; } // user-defined destructor: no implicit copy or move
Handle(Handle&& h) :p{h.p} { h.p=nullptr; }; // transfer ownership
Handle& operator=(Handle&& h) { delete p; p=h.p; h.p=nullptr; return *this; } // transfer ownership
Handle(const Handle&) = delete; // no copy
Handle& operator=(const Handle&) = delete;
// ...
};
What does "transfer ownership" mean?
Why is the copy ctor equated to "delete"? how is it useful?
Please if someone can add a few examples with explanation, it would be a great help.
It's a move constructor, the special && syntax introduced in C++11 takes a rvalue reference, so a reference to a variable which has no name and can't be referenced anywhere else inside the code.
What happens in the constructor is that the Handle takes the ownership of the Handle passed through the move constructor in the way that it steals (pass me the term) the T* p inside by assigning its value to its own variable and then setting nullptr to the variable of the rvalue passed.
This is used because you don't really need to copy an rvalue, since that value won't be used anymore in the code, so it's safe to just take its data, this avoids a, possibly costly, copy constructor.
In C++ you had copy constructors and copy operators, which were expensive if your object was big. Now in C++11 you have move constructor and move operator which says "take everything from the source and kill it".
mybigthing y ;
...
mybigthing x( move(y)) ;
y is created with lots of stuff internally. after x(y), y is now empty and all the big stuff is in x.
One of the main reasons for this is to make returning big objects from functions free:
mybigthing f()
{
mybigthing tmp ;
...
return tmp ;
}
{
mybigthing y= f() ;
}
In c++03, this would be horrible performance wise. Now its free. The compilers are required to actually use y as the temporary inside of f() and never do any copies.
transfer ownership means if you do a=b the contents of b belong to a and does not exist in b anymore. This makes more sense in the example {A a; dosomething(a); return a;}. a exist locally in the function. It's contents are being moved into the return value. If A is a typedef for std::string it would mean the string internals have been moved instead of making a copy of a intentionally long string (html page maybe). However I believe string has a copy on write flag so it wouldn't make a copy in that situation but other classes may not bother to implement a copy on write.
The reason the constructor and assignment operator (which are move, not copy) delete is because the current p may be pointing to something. Not freeing it means a memory leak.
about your second question:
Why is the copy ctor equated to "delete"? how is it useful?
Here is an answer:
http://www.developerfusion.com/article/133063/constructors-in-c11/
C++11 Explicitly Deleted Constructors
C++11 also supports the concept of explicitly deleted constructors.
For example, you can define a class for which you do not want to write
any constructors and you also do not want the compiler to generate the
default constructor. In that case you need to explicitly delete the
default constructor:
class MyClass { public:
MyClass() = delete; };
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;
i m trying to make a simple program ( & yes , it is a homework ) that can generate Dates , & like most of normal people : i made my Class attributes private , i tried to send the same type that i m working on to the constructor but the complier have not accept it , i did some research & i found out that in cases like that people generously send a const "type" reference to the constructor witch meant to me that have not understand OOP well
so why do we have to send the const " type " reference instead of just the types name to the constructor ? & please give me some links or websites for beginners
here is a peace of my Code :
class Date {
int d ;
int m ;
int y ;
public :
Date();
Date(int , int , int);
Date(const Date &);// my question is : why do we have to write this instead of Date( Date )
};
PS : sorry for my English
To paraphrase our question:
why do we have to write Date(const Date &) instead of Date(Date)?
I'm going to split this into two parts, the first answering why a copy constructor needs to take its argument per reference, the second why this needs to be a const reference.
The reason a copy constructor needs to take its argument per reference is that, for a function that's taking an argument per copy void f(T arg), when you call it f(obj), obj is copied into arg using T's copy constructor. So if you want to implement the copy constructor, you'd better not take the argument by copy, because this would call the copy constructor while invoking it, leading to an endless recursion. You can easily try this yourself:
struct tester {
tester(tester) {std::cout << "inside of erroneous copy ctor\n";}
};
int main()
{
tester t1;
std::cout << "about to call erroneous copy ctor\n";
tester t2(t1);
std::cout << "done with call erroneous copy ctor\n";
return 0;
}
That program should only ever write one line and then blow the stack.
Note: As Dennis points out in his comment, actually this program is not guaranteed to compile, so, depending on your compiler, you might not really be able to try it.
Bottom line: A copy constructor should take its argument by reference, because taking it per copy would require the copy constructor.
That leaves the question of why it is const T& and not simply T&? In fact, there are two reasons for that.
The logical reason is that, when you invoke the copy constructor, you do not expect the object copied from to change. In C++, if you want to express that something is immutable, you use const. This tells users that they can safely pass their precious objects to your copy constructor, because it won't do anything with it except read from it. As a nice side effect, if you implement the copy constructor and accidentally try to write to the object, the compiler throws an error message at you, reminding you of the promise made to the caller.
The other reason is that you cannot bind temporary objects to non-const references, you can only bind them to const references. A temporary object is, for example, what a function might return:
struct tester {
tester(tester& rhs) {std::cout << "inside of erroneous copy ctor\n";}
};
tester void f()
{
tester t;
return t;
}
When f() is called, a tester object is created inside, and a copy of it is then returned to the caller, which might then put it into another copy:
tester my_t = f(); // won't compile
The problem is that f() returns a temporary object, and in order to call the copy constructor, this temporary would need to bind to the rhs argument of tester's copy constructor, which is a non-const reference. But you cannot bind a temporary object to a non-const reference, so that code won't compile.
While you can work around this if you want (just don't copy the temporary, but bind it to a const reference instead, which extends the temporary's lifetime to the end of the reference's lifetime: const tester& my_t = f()), people expect to be able to copy temporaries of your type.
Bottom line: A copy constructor should take its argument by const reference, because otherwise users might not be willing or able to use it.
Here's one more fact: In the next C++ standard, you can overload functions for temporary objects, so-called rvalues. So you can have a special copy constructor that takes temporary objects overloading the "normal" copy constructor. If you have a compiler that already supports this new feature, you can try it out:
struct tester {
tester(const tester& rhs) { std::cout << "common copy ctor\n"; }
tester( tester&& rhs) { std::cout << "copy ctor for rvalues\n"; }
};
When you use the above code to invoke our f()
tester my_t = f();
the new copy constructor for rvalues should be called when the temporary object returned by the call to f() is copied to my_t and the regular copy constructor might be called in order to copy the t object from inside of f() to the returned temporary. (Note: you might have to disable your compiler's optimization in order to see this, as the compiler is allowed to optimize away all the copying.)
So what can you with this? Well, when you copy an rvalue, you know that the object copied from is going to be destroyed after the call to the copy constructor, so the copy constructor taking an rvalue (T&&) could just steal the values from the argument instead of copying them. Since the object is going to be destroyed anyway, nobody is going to notice.
For some classes (for example, for string classes), moving the value from one object to another could be much cheaper than copying them.
if I understood your question correctly, to avoid making copies/calling constructor of object.
void function(const T&); // does not create new T
void function(T&); // does not create newT, however T must be modifiable (lvalue)
void function(T); // creates new T
for simple types creating new copy is trivial (and often optimized away by compiler).
For complex object, creating new copy may be very expensive.
Hence you pass it by reference.
https://isocpp.org/wiki/faq/references
https://isocpp.org/wiki/faq/ctors
if you are asking why can not do the following:
struct type {
type(type);
};
Is because this would lead to infinite recursion, since constructor depends on itself
you can do this however
struct type {
type(type, int);
};
since this constructor is different from synthesized type(const type&)
http://en.wikipedia.org/wiki/Copy_constructor
In addition to #aaa's answer, I will try to answer the const part. The const part simply means that the object you are passing logically does not change. This makes sense, because when a copy constructor is called with a Date object argument d, d should not be modified at all!
You can remove the const and your code will still work the same way. However, const provides the additional security that you can never modify the variable marked as const. In your case, this means you can not call any of the non-const method of Date. This is enforced by the compiler at compile-time.
Historically this is the reason for introducing references to the language. Here's an explanation:
In C you can pass values to parameters by value (void f(struct custom_type i)) or by pointer (void g(struct custom_type* i)).
With POD values (int, char, etc.) passing by value is not a problem, but if you are looking at complex structures, then the stack grows too quickly by placing entire structures on stack for function calls. That is why in C you tend to pass structures as parameters by pointer, even if the function doesn't modify them.
In C++ there are cases where neither option worked:
passing by pointers involves a counter-intuitive syntax for operators (if you define operator + for a class custom_type writing custom_type a, b, c; a = &b + &c; is counterintuitive as a doesn't get assigned the sum of the addresses. Furthermore if you wanted to be able to assign the sum of the values to a and the sum of the addresses to a, you would have to somehow differentiate between the cases, by syntax).
passing by value is impossible or undesired in the case of copy constructors. In your case, if you have Date(Date d) {} and assignment Date a; Date b(a); what you get is that a copy of a is created just to be passed as a parameter to the constructor of b. This leads to infinite recursion, as creating a copy of a to pass as a parameter involves is the same as Date d = a; b = Date(d);.
For these reasons (and there may have been others) a decision was made to create references: data types that looks syntactically like a value type, but behave like pointers (that is, it points to the value of another variable, but you access it like a variable, not like a pointer).
Regarding the reason why you need const in the declaration, it is so that your constructor will accept temporary objects. As you cannot modify the value of a temporary references if your constructor doesn't accept const& you can only use the copy constructor for non-const stable objects.
That is, if you have:
class Date
{
public:
Date(Date& other); // non-const reference
...
you can write:
Date a;
Date b = a;
but not:
Date someFunction() { return Date(xxx); }
Date a = someFunction(); // someFunction returns a temporary object
neither:
const Date someImportantDate;
Date a = someImportantDate; // cannot pass const value to non-const