Ok i will try my best to explain and if you find any mistakes forgive me.
First of all we have to understand what is std::move(...)
?
std::move(...)
takes a object and returns a rvalue reference. Thats it. Now when creating a new object we can use that rvalue reference to invoke move constructor where actual
move operations happens. (cheap copy).
Lets see an example
#include <iostream>
#include <cstring>
#include <cstdlib>
using std::cout;
struct foo
{
int *resource;
foo()
: resource{new int[10]}
{
cout << "c'tor called\n";
}
foo(const foo &arg)
:foo{} // delegating constructors. calls above constructor first then execute my body.
{
/* Here expensive copy happens */
memcpy(resource, arg.resource, 10);
cout << "copy c'tor called\n";
}
foo(foo &&arg)
: resource{arg.resource} // just change ownership of resource.
{
/*
Here actual move happens.
Its implementator's job.
*/
cout << "move c'tor called\n";
arg.resource = nullptr;
}
};
int main()
{
foo a{};
foo b{a}; // calls copy constructor
/*
Do some stuff with a and b
*/
foo c{std::move(a)} // calls move constructor
}
Here i create foo a
object, where i initialise resource with new chunk of memory. Nothing fancy here.
In second line new object b
is created by passing object a
as argument. The copy constructor is invoked and as a result object b
is same as object a
.
Now i think of creating another object which should be same as a
, and at same time i know that i wont be using object a
anymore, so i do foo c{std::move(a)}
.
i could have also done foo c{a}
, but as i know i wont be using a
anymore so swapping the contents of object is far efficient.
Inside move constructor i need to make sure to do this arg.resource = nullptr
. if i wont do this, and if somebody by accident changes object a
this will indirectly effect object c
too.
After doing that object a
is still valid and exists. Only the contents have changed. Now coming to question
std::string x = std::move(v[0]);
Ok creating new string object by calling move constructor.
After this operation the v[0] still exists only the inside constents of v[0] have changed. so v.size() is 2.
auto y = std::move(v);
after this operation new vector object y
is created by calling move constructor.
Inside move constructor of vector the implementor have to do something like this
arg.container_size = 0;
Because the contents of vector have new owner.