6

I was reading std template library book and was confused with below details listed in STL Containers chapter. Apparently, it specifies the STD::VECTOR Operations and the effect

Operation                     Effect

vector<Elem> c(c2)  | Copy constructor; creates a new vector as a copy of c2 (all elements are copied)
vector<Elem> c = c2 | Copy constructor; creates a new vector as a copy of c2 (all elements are copied)
vector<Elem> c(rv)  | Move constructor; creates a new vector, taking the contents of the rvalue rv (since C++11)
vector<Elem> c = rv | Move constructor; creates a new vector, taking the contents of the rvalue rv (since C++11)

Apparently, there is no difference in the syntax for both move and copy constructors, when exactly are they called?

Cœur
  • 37,241
  • 25
  • 195
  • 267
LearningCpp
  • 972
  • 12
  • 29
  • 4
    Without an explicit `std::move` call, it's up to the compiler. There might be some rules in the specification, but AFAIK it's mostly up to the compiler. If you pass an r-value then the compiler is smart enough that it calls the move constructor. – Some programmer dude Sep 06 '16 at 11:32
  • Also note that when initializing a variable, the use of `=` does not mean assignment the same way as when you do an assignment later. Example: `int a = 5;` is an *initialization*, while `int a; a = 5;` is an *assignment*. – Some programmer dude Sep 06 '16 at 11:34
  • @JoachimPileborg my confusion is when does compiler decide to call move or copy constructor, the calls are just identical for both – LearningCpp Sep 06 '16 at 11:35
  • Look at the difference between `c2` and `rv`: `rv` is an _r-value_, if you are trying to copy or assingn it, compiler will call move version of constructor/operator if it exist. – Revolver_Ocelot Sep 06 '16 at 11:40
  • @Revolver_Ocelot : i assume rv is just a constructed object like c2 is , please explain if anything different – LearningCpp Sep 06 '16 at 11:42
  • @LearningCpp I've taken your confusion into account in my answer. – eerorika Sep 06 '16 at 12:09
  • You should look up on r-values to understand the `rv`. In general r-values are temporary objects or after `std::move` was called. – Hayt Sep 06 '16 at 12:24
  • smbclient "\\\\reports\\Reports$\\" -Uptp%Password01 -c"cd 20180328" – LearningCpp Apr 05 '18 at 11:52

5 Answers5

6

Let say you have a function f that returns a vector by value:

std::vector<int> f();

The value returned by the function is an rvalue.

And then lets say you want to call this function to initialize a vector of yours:

std::vector<int> v = f();

Now the compiler knows the vector returned by f will not be used any more, it's a temporary object, therefore it doesn't make sense to copy this temporary object since it will just be destructed at once anyway. So the compiler decides to call the move-constructor instead.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
6

The move constructor is called where it makes sense to call it, i.e. moving an object and using it thereafter does not make sense, as the original object has been modified (possibly), which is not desirable:

std::vector<int> a = { 1 };
std::vector<int> b = a; //Let's say this called move constructor
int value = a[0]; //value is possibly not 1, the value may have changed due to the move

So, in that case, the copy constructor is called:

std::vector<int> a = { 1, 2 };
std::vector<int> b = a; //Copy constructor

But, here it does call the move constructor, because it is assigned to an rvalue, or a temporary value:

void foo(std::vector<int>) {}
foo({ 1, 2 }); //move constructor

The vector { 1, 2 } is a temporary vector, who cares if it has been modified? You will never know, as the vector will get destructed as soon as foo has ended. Copying the temporary vector would just be a waste of time.

Rakete1111
  • 47,013
  • 16
  • 123
  • 162
3

Apparently , there is no difference in the syntax for both move and copy constructors

Indeed, this is true. This is not specific to std::vector either, but holds in general for all types. Copy-initialization by copy and by move have exactly the same syntax. Same goes for copy-assignment.

The difference comes from the type of argument expression. When the argument is a non-const r-value, the move constructor/assignment is preferred by overload resolution. Otherwise, move-constructor is not applicable, so copy constructor is used.

i assume rv is just a constructed object like c2

rv and c2 appear to not be objects. They are apparently placeholders for expressions. The book could be clearer about that (maybe it is, the excerpt is out of context after all).

eerorika
  • 232,697
  • 12
  • 197
  • 326
2

Perhaps you should decouple syntax from semantics for better understanding. Let me make an analogy, consider this code.

struct A {
  A(int i) {}
  A(const std::string& s) {}
};

Now, if you find the following line, which constructor will be called?

A a(x);

You can't tell it because you don't know whether x has type int or std::string. It's not much different in your example, but with move semantics the compiler will inspect whether the argument is an rvalue or not. If such an A class provides a (move) constructor overload and x is an rvalue reference, then it will be preferred.

Leandro T. C. Melo
  • 3,974
  • 22
  • 22
-1

syntax of copy constructor: classname (const classname&)

syntax of move constructor: classname (classname&&)

The calling looks same together but their declarations are different.

Ref:

http://en.cppreference.com/w/cpp/language/copy_constructor http://en.cppreference.com/w/cpp/language/move_constructor

Khoa
  • 2,632
  • 18
  • 13
  • Yeah, What makes the compiler call move constructor , if the usage is identical.How does the compiler decide Any Idea ? – LearningCpp Sep 06 '16 at 11:36
  • To call move constructor you do like this: T a(std::move(b)) . This is explicit case. For implicit case please read ref for more details: – Khoa Sep 06 '16 at 11:43
  • @LearningCpp - look at the first comment of JoachimPileborg: if you write `std::vector v1; std::vector v2(v1);`, for `v2` is called the copy constructor because you could use `v1` again; if you write `std::vector v1; std::vector v2(std::move(v1));`, for `v2` is called the move constructor because, with `std::move()` you are saying to the compiler "I'm not using `v1` anymore". – max66 Sep 06 '16 at 11:44