Behaviour of std::move operation in c++11 - c++

#include <string>
#include <iostream>
#include <utility>
struct A {
std::string s;
A() : s("test") {}
A(const A& o) : s(o.s) { std::cout << "move failed!\n"; }
A(A&& o) : s(std::move(o.s)) {}
A& operator=(const A&) { std::cout << "copy assigned\n"; return *this; }
A& operator=(A&& other) {
s = std::move(other.s);
std::cout << "move assigned\n";`enter code here`
return *this;
}
};
A f(A a) { return a; }
struct B : A {
std::string s2;
int n;
// implicit move assignment operator B& B::operator=(B&&)
// calls A's move assignment operator
// calls s2's move assignment operator
// and makes a bitwise copy of n
};
struct C : B {
~C() {}; // destructor prevents implicit move assignment
};
struct D : B {
D() {}
~D() {}; // destructor would prevent implicit move assignment
//D& operator=(D&&) = default; // force a move assignment anyway
};
int main()
{
A a1, a2;
std::cout << "Trying to move-assign A from rvalue temporary\n";
a1 = f(A()); // move-assignment from rvalue temporary
std::cout << "Trying to move-assign A from xvalue\n";
a2 = std::move(a1); // move-assignment from xvalue
std::cout << "Trying to move-assign B\n";
B b1, b2;
std::cout << "Before move, b1.s = \"" << b1.s << "\"\n";
b2 = std::move(b1); // calls implicit move assignment
std::cout << "After move, b1.s = \"" << b1.s << "\"\n";
std::cout << "Trying to move-assign C\n";
C c1, c2;
c2 = std::move(c1); // calls the copy assignment operator
std::cout << "Trying to move-assign D\n";
D d1, d2;
// d2 = std::move(d1);
}
While executing a2 = std::move(a1) statement, the behaviour is different from executing the statement b2 = std::move(b1). In the below statement the b1.s is not becoming empty after the move operation while a1.s is becoming empty after move operation.
Can anyone tell what exactly is happening there?

One of the great (and constant) misconceptions about C++11 and rvalue references is that std::move does something to an object (or something on that order).
It doesn't. std::move really just casts its parameter to rvalue reference type and returns that. Anything done to the object happens in the move constructor, move assignment operator (etc.) based on the fact that the version that takes an rvalue reference is invoked (instead of one taking a value or lvalue reference).
As far as the specific question you asked goes, at least based on the comments in your code, you seem to have some misunderstandings. The comment on a2=std::move(a1); says you're doing a "move assignment from an xvalue". That's...misleading at best. An xvalue is a value that's going to eXpire immediately. It's pretty much for the return value from a function:
Foo &&bar() {
Foo f;
// ...
return f;
}
In this case, bar() is an xvalue because bar returns an rvalue reference to an object that expires (goes out of scope) as function finishes execution.
As far as the specific question you asked goes, I suspect it mostly comes down to a question of whether (and if so, exactly how) your standard library implements the move constructor for std::string. Just for example, when using g++ (4.9.1) I get the same result you do--b1.s contains test both before and after being used as the source of a move. On the other hand, if I use MS VC++ 14 CTP, I get b1.s="test" before the move and b1.s="" after the move. Although I haven't tested it, I'd expect results with Clang to be the same. In short, it looks like gcc's standard library doesn't really implement move assignment/construction for std::string (yet--at least as of v 4.9--I haven't looked at 5.0 yet).

Usually move assignment is implemented as a swap on std::string, so why should the string become empty since it's always initialized with "test"?
Where do you see that a1.s is becoming empty since there is no print of it?
I don't see any strange behavior here. Both are treated in the same way.

Related

C++ Move constructor not called with the compound operator += when written in one line

I followed the amazing tutorials from stackoverflow for Move and Operator overloading (e.g. What are the basic rules and idioms for operator overloading?), and the following situation is baffling me. Nothing fancy in the code, just printing when special member functions are called.
The main code:
class B {
public:
B() { std::cout << "B::ctor\n"; }
~B() { std::cout << "B::dtor\n"; }
B(B const &b) {
std::cout << "B::copy ctor\n";
}
B &operator=(B const &rhs) {
std::cout << "B::copy assignment\n";
return *this;
}
B(B &&b) {
std::cout << "B::move ctor\n";
}
B &operator=(B &&rhs) {
std::cout << "B::move assignment\n";
return *this;
}
B &operator+=(B const &rhs) {
std::cout << "B::operator+=\n";
return *this;
}
};
int main() {
B b;
std::cout << "=== b = b + b + b ===\n";
b = b + b + b;
}
Now, two scenarios, where in each I define the operator + differently:
B operator+(B p1, B const &p2) {
std::cout << "B::operator+\n";
return p1 += p2;
}
with output for the whole program:
B::ctor
=== b = b + b + b ===
B::copy ctor
B::operator+
B::operator+=
B::copy ctor
B::operator+
B::operator+=
B::copy ctor
B::move assignment
B::dtor
B::dtor
B::dtor
B::dtor
and the second scenario:
B operator+(B p1, B const &p2) {
std::cout << "B::operator+\n";
p1 += p2;
return p1;
}
with output:
B::ctor
=== b = b + b + b ===
B::copy ctor
B::operator+
B::operator+=
B::move ctor
B::operator+
B::operator+=
B::move ctor
B::move assignment
B::dtor
B::dtor
B::dtor
B::dtor
How come the second scenario does give the expected result, using correctly the move semantics, but the first makes copy everywhere?
I just want to add that the second scenario is the one recommended in the tutorials I read (like the link from above), but when I tried to implement it, I intuitively wrote the first scenario and it gave me the wrong behaviour...
Returning a local variable of type T from a function with with the same1 return type T is a special case.
It at least automatically moves the variable, or, if the compiler is smart enough to perform so-called NRVO, eliminates the copy/move entirely and constructs the variable directly in the right location.
Function parameters (unlike regular local variables) are not eligible for NRVO, so you always get an implicit move in (2).
This doesn't happen in (1). The compiler isn't going to analyze += to understand what it returns; this rule only works when the operand of return is a single variable.
Since += returns an lvalue reference, and you didn't std::move it, the copy constructor is called.
1 Or a type that differs only in cv-qualifiers.

What is the difference between rvalue reference and lvalue reference?

After reading some materiales about rvalue reference i have more question then answers. From here i have read about rvalue ref:
Doc rvalue ref (1)
Doc rvalue ref (2)
Doc rvalue ref (3 - book)
Here i made a simple example to help me understand:
#include <iostream>
using namespace std;
class A
{
public:
A() :m_a(0), m_pa(nullptr) { cout << "constructor call" << endl; };
~A() { cout << "destructor call" << endl; };
A(A& other) :m_a(0), m_pa(nullptr)
{
cout << "copy constructor" << endl;
}
A(A&& other) :m_a(0), m_pa(nullptr)
{
cout << "move constructor" << endl;
}
A& operator=(A&& other)
{
this->m_a = other.m_a;
this->m_pa = other.m_pa;
other.m_a = 0;
other.m_pa = nullptr;
return *this;
}
A& operator=(A& other)
{
this->m_a = other.m_a;
this->m_pa = other.m_pa;
other.m_a = 0;
other.m_pa = nullptr;
return *this;
}
private:
int m_a;
int* m_pa;
};
int main()
{
A(test2);//constructor
A test4(test2);//copy constructor
//? - move constructor
return 0;
}
I don't understand what is so special with &&. In the above example i can do something like this with &.
A& operator=(A& other)
{
this->m_a = other.m_a; //copy value
this->m_pa = other.m_pa;//copy pointer address
other.m_a = 0;
other.m_pa = nullptr;//clean "other" object properties from preventing destructor to delete them and lose pointer address
return *this;
}
Question:
If i can do this with & without using extra memory allocation and copy operation why should i use &&?
How is a value value taken that has no identifier and saved?
Example 2:
#include <iostream>
using namespace std;
void printReference (int& value)
{
cout << "lvalue: value = " << value << endl;
}
void printReference (int&& value)
{
cout << "rvalue: value = " << value << endl;
}
int getValue ()
{
int temp_ii = 99;
return temp_ii;
}
int main()
{
int ii = 11;
printReference(ii);
printReference(getValue()); // printReference(99);
return 0;
}
Question:
Why to use && in this case and how does this help me? Why not just store the return of getValue and print it?
After you read some stuff about rvalues, here is some more material about rvalues.
I think the point you are probably missing, is not (only) what you can do but what you should do.
Your first example has several issues:
Your are not able to copy a const value to an instance of A.
const A a1;
A a2(a1); // won't compile
A a3;
a3 = a1; // won't compile
I don't understand what is so special with &&. In the above example i can do something like this with &.
Yes you could do what you suggested. But it is purely designed copy assigment. Consider this:
I wrote a shared library where my copy ctor is like you did in your suggestion. You don't have access to my code, just the header. In my copy ctor and assigment operator i take ownership of the instance you passed to my library. There is no description what the assignment is doing... Do you see the point, I must not take ownership of your instances! eg:
// my header:
// copy ctor
A& operator=(A& other);
// your code:
A a1;
A a2(a1); // from now on, a1 is broken and you don't know it!!!
cout << a1; // pseudo code: prints garbage, UD, crash!!!
You always should define copy-ctors/assignments parameters const:
A(A const& other);
A& operator=(A const& other);
// ...
const A a1;
A a2(a1); // will compile
A a3;
a3 = a1; // will compile + due to the fact a1 is passed const a3 cannot mutate a1 (does not take ownership)
cout << a1; // pseudo code: everything is fine
a3 = std::move(a1); // a3 takes ownership from a1 but you stated this explicitly as you want it
Here is a small example you can play with. Notice the copy constructor is const but the copy assignment is not. Then you can see how they differ.
If i can do this with & without using extra memory allocation and copy operation why should i use &&?
The assignment operators you wrote taking & lvalue references are very, very bad. You don't expect statements like
a = b;
to damage b, but that's what you're suggesting. The usual assignment operator takes a const& precisely because it shouldn't alter the right-hand-side of the expression.
So, you should use the rvalue-reference assignment operator (move assignment) when you do want to steal the right-hand-side's state, such as when it's an anonymous temporary or you explicitly move it:
a = return_anonymous_temporary(); // ok: the rhs value would expire anyway
a = std::move(b); // ok: the damage to b is explicit now
That behaviour shouldn't be the default, though.
If i can do this with & without using extra memory allocation and copy operation why should i use &&?
Because it allows you to overload a function for rvalues and lvalues and have different behaviour for each. You have same behaviour in both overloads, so you don't need an rvalue reference in this case.
More generally, an rvalue reference argument allows you to pass a temporary, while allowing a move from that argument.
Why to use && in this case and how does this help me?
It allowed you to print "rvalue" when the argument was an rvalue.
Why not just store the return of getValue and print it?
Then you won't be able to print "rvalue" for rvalues and "lvalue" for lvalues.
Except for move constructor/assignment operator, there are not many cases where r-values are useful.

Difference between && and no ref in return type [duplicate]

This question already has an answer here:
Difference between "return-by-rvalue-ref" & "return-by-value" when you return using std::move?
(1 answer)
Closed 6 years ago.
Is there a difference in behavior when the return type is explicitly declared rvalue vs no ref? According to the example below, there doesn't seem to be any difference.
#include <iostream>
#include <vector>
using namespace std;
struct A {
A(int x) : x_(x) {}
A(A&&) = default; // VC12 hasn't implemented default move
A(const A&) = delete;
A& operator=(A&&) = default;
A& operator=(const A&) = delete;
vector<int> x_;
};
struct B{
B(int x) : a_(x) {}
A&& foo1() { return move(a_); } // explicitly declared as rvalue
A foo2() { return move(a_); } // no ref
A a_;
};
int main() {
B b1(7);
A a1 = b1.foo1();
B b2(7);
A a2 = b2.foo2();
cout << a1.x_.size() << ' ' << a2.x_.size() << endl;
cout << b1.a_.x_.size() << ' ' << b2.a_.x_.size() << endl;
return 0;
}
This example has been compiled by Ideone's C++14 compiler (not sure of the exact version, I suspect it's gnu 5.1) and VC12 (Visual Studio 2013). The only minor difference is VC12 requires an explicit move implementation.
Edit: A related SO post said that the two function end up doing the same thing. However, "in many cases it allows the compiler to perform copy elision and elide the calls to the move constructor of the returned type, as permitted by paragraph 12.8/31 of the C++11 Standard". "Copy elision allows the compiler to create the return value of the function directly in the object."
Question 1: Copy elision should still happen when move is explicitly called, right?
Question 2:
When move is explicitly called on a lvalue (so a required called), A&& and A means the same behavior. When move is not explicitly called, meaning the compiler performs copy elision, A should be the only return type. Combining the two scenario above, can I conclude that return type A&& is not useful and only adds confusion?
With
A&& foo1() { return move(a_); }
A foo2() { return move(a_); }
foo1 returns a (rvalue) reference.
foo2 construct an object A with the move constructor.

None of the copy/move constructor/assignment is called while initializing [duplicate]

This question already has answers here:
What are copy elision and return value optimization?
(5 answers)
Closed 8 years ago.
Class A defines all copy/move constructor/assignment as follows:
struct A
{
std::string s;
A() : s("test") { }
A(const A& other) : s(other.s) { std::cout << "Copy constructor\n";}
A(A&& other) : s(std::move(other.s)) { std::cout << "Move constructor\n";}
A& operator= (const A& other) { std::cout << "Copy assignment\n"; s = other.s; return *this;}
A& operator= (A&& other) { std::cout << "Move assignment\n"; s = std::move(other.s); return *this;}
};
And the followings are functions returning an object of type A:
A f(A a) { return a; }
A g() { return A(); }
The main() function is this:
int main()
{
A a1 = f(A()); // Move-construct
A a2 = std::move(a1); // Move-construct
A a3 (std::move(a2)); // Move-construct
A a4 (a1); // Copy-construct
A a5 = a4; // Copy-construct
a5 = f(A()); // Move constructor + Move assignment
a5 = a4; // Copy assignment
a5 = g(); // Move assignment
A a6 = g(); // None!! Member-wise assignment (?)
}
Can anybody tell me, why on earth none of the constructors and assignment operators is called for a6? Which part of C++11's documentation describes this behavior?
This is called copy elision and is described in C++ standard, section 12.8 pt 31.
When certain criteria are met, an implementation is allowed to omit
the copy/move construction of a class object, even if the constructor
selected for the copy/move operation and/or the destructor for the
object have side effects. In such cases, the implementation treats the
source and target of the omitted copy/move operation as simply two
different ways of referring to the same object (...)
The circumstances are described as well. One of which being:
when a temporary class object that has not been bound to a reference
would be copied/moved to a class object with the same cv-unqualified
type, the copy/move operation can be omitted by constructing the
temporary object directly into the target of the omitted copy/move
As g() returns a temporary anonymous object (not bound to a reference), is is constructed directly into the target a6. In your example, the default constructor of g's return statement is used.
With http://en.wikipedia.org/wiki/Return_value_optimization in A a6 = g();, the code within g creates a6 by calling one of the A constructors somewhere in the middle of the body of g.

When will the move ctor be invoked?

Given class:
class C
{
public:
C()
{
cout << "Dflt ctor.";
}
C(C& obj)
{
cout << "Copy ctor.";
}
C(C&& obj)
{
cout << "Move ctor.";
}
C& operator=(C& obj)
{
cout << "operator=";
return obj;
}
C& operator=(C&& obj)
{
cout << "Move operator=";
return obj;
}
};
and then in main:
int main(int argc, char* argv[])
{
C c;
C d = c;
C e;
e = c;
return 0;
}
as you will see from the output the "regular" version of copy ctor and operator= are invoked but not those with rvalue args. So I would like to ask in what circumstances will the move ctor and operator=(C&&) be invoked?
The move constructor will be invoked when the right-hand side is a temporary, or something that has been explicitly cast to C&& either using static_cast<C&&> or std::move.
C c;
C d(std::move(c)); // move constructor
C e(static_cast<C&&>(c)); // move constructor
C f;
f=std::move(c); // move assignment
f=static_cast<C&&>(c); // move assignment
C g((C())); // move construct from temporary (extra parens needed for parsing)
f=C(); // move assign from temporary
IIRC, you have to use C d = std::move(c) to use the move constructor.
An example not tested but that could explain better the use of move constructor :
C&& foo() { C c; return std::move(c); }
All of your variables are lvalues and thus cannot be moved implicitly, since you may need to access them later. In addition, copy constructors and assignment operators take const references.
Rvalue references work on, well, rvalues, that is, temporary objects. In order to see the move constructor used, first, you will have to actually create a temporary object. In addition, don't forget that RVO still applies and may well nail any or all of your std::cout calls.
You can create an rvalue from an lvalue using std::move(lvalue).
std::swap(c,e); // c and e variables declared in your _tmain()
would call the move constructor.
More realistic example of using move operator would be if you have a static class which returns C&& created on the local stack like this:
static C&& CreateC()
{
C c();
//do something with your object
return c;
}
and then you invoke it like this:
C x = CreateC(); // move operator is invoked here