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.
Related
I have this code, taken from here by the way http://www.cplusplus.com/doc/tutorial/classes2/
// move constructor/assignment
#include <iostream>
#include <string>
#include <utility>
using namespace std;
class Example6
{
string* ptr;
public:
Example6(const string& str) :
ptr(new string(str))
{
cout << "DONT MOVE " << '\n';
}
~Example6()
{
delete ptr;
}
// move constructor
Example6(Example6&& x) :
ptr(x.ptr)
{
cout << "MOVE " << '\n';
x.ptr = nullptr;
}
// move assignment
Example6& operator=(Example6&& x)
{
delete ptr;
ptr = x.ptr;
x.ptr = nullptr;
return *this;
}
// access content:
const string& content() const
{
return *ptr;
}
// addition:
Example6 operator+(const Example6& rhs)
{
return Example6(content() + rhs.content());
}
};
int main()
{
Example6 foo("Exam");
Example6 bar = Example6("ple"); // move-construction
foo = foo + bar; // move-assignment
cout << "foo's content: " << foo.content() << '\n';
return 0;
}
I only added output in constructor to see which is being called. To my surprise it is always the first one, copy constructor. Why does it happen? I did some research and found some info about elision. Is it somehow possible to prevent it and always call move constructor?
Also, as a side note, as I said this code is from cplusplus.com. However, I read about move semantics in some other places and I wonder if this move constructor here is done right. Shouldn't it call
ptr(move(x.ptr))
instead of just
ptr(x.ptr)
The way I understand this, if we use the second option, then we are calling copy constructor of string, instead of move, because x is rvalue reference that has a name, so it is really lvalue and we need to use move to cast it to be rvalue. Do i miss something, or is it really tutorial's mistake?
Btw, adding move doesn't solve my first problem.
So anything with a name is an lvalue.
An rvalue reference with a name is an lvalue.
An rvalue reference will bind to rvalues, but it itself is an lvalue.
So x in ptr(x.ptr) is an rvalue reference, but it has a name, so it is an lvalue.
To treat it as an rvalue, you need to do ptr( std::move(x).ptr ).
Of course, this is mostly useless, as moving a ptr does nothing as ptr is a dumb raw pointer.
You should be following the rule of 0 here.
class Example6 {
std::unique_ptr<string> ptr;
public:
Example6 (string str) : ptr(std::make_unique<string>(std::move(str))) {cout << "DONT MOVE " << '\n';}
Example6():Example6("") {}
~Example6 () = default;
// move constructor
Example6 (Example6&& x) = default;
// move assignment
Example6& operator= (Example6&& x) = default;
// access content:
const string& content() const {
if (!ptr) *this=Example6{};
return *ptr;
}
// addition:
Example6 operator+(const Example6& rhs) {
return Example6(content()+rhs.content());
}
};
because business logic and lifetime management don't belong intermixed in the same class.
While we are at it:
// addition:
Example6& operator+=(const Example6& rhs) & {
if (!ptr) *this = Example6{};
*ptr += rhs.content();
return *this;
}
// addition:
friend Example6 operator+(Example6 lhs, const Example6& rhs) {
lhs += rhs;
return lhs;
}
Copy constructor is called ... - why?
The premise of your question is faulty: The copy constructor is not called. In fact, the class is not copyable.
The first constructor is a converting constructor from std::string. The converting constructor is called because Example6 objects are initialised with a string argument. Once in each of these expressions:
Example6 foo("Exam")
Example6("ple")
Example6(content() + rhs.content()
... instead of move constructor
There are a few copy-initialisations by move in the program. However, all of them can be elided by the compiler.
Is it somehow possible to prevent it and always call move constructor?
There are a few mistakes that can prevent copy elision. For example, if you wrote the addition operator like this:
return std::move(Example6(content()+rhs.content()));
The compiler would fail to elide the move and probably tell you about it if you're lucky:
warning: moving a temporary object prevents copy elision
Shouldn't it call
ptr(move(x.ptr))
instead of just
ptr(x.ptr)
There's no need. Moving a pointer is exactly the same as copying a pointer. Same holds for all fundamental types.
The way I understand this, if we use the second option, then we are calling copy constructor of string, instead of move
ptr is not a string. It is a pointer to a string. Copying a pointer does nothing to the pointed object.
PS. The example program is quite bad quality. There should never be owning bare pointers in C++.
I can say your class does not have a copy constructor.
Because copy ctor parameter have to be const and reference
class Example6{
public:
Example6(const Example6 &r);
};
#include <iostream>
using namespace std;
class Test {
public:
Test() {
cout << "Default constructor called." << endl;
}
Test(Test &obj) {
cout << "copy constructor called." << endl;
}
Test& operator=(const Test &obj) {
cout << "copy assignment called." << endl;
return *this;
}
~Test() {
cout << "destructor called." << endl;
}
};
Test func(Test test) {
cout << "func called" << endl;
return test;
}
int main(int argc, char* argv[]) {
Test t1;
Test t2 = func(t1); // No matching constructor for initialization for 'Test'
return 0;
}
I am learning c++. I wrote some test code to understand copy initialization and copy assignment. Now I can not figure out why the second assignment can not work.
An rvalue cannot be modified, and should, in this case, be treated as a const reference const Test& obj. So when you convert t1 into the test in func, it's OK because t1 is an lvalue, but not when you're constucting t2 from the return value, which is an xvalue (categorized into rvalue).
In short, the signature of your copy constructor is wrong because it only accepts lvalues.
The following patch on line 10 makes the code work for me.
Test(const Test &obj) {
^~~~~
Here's the article about copy constructor on cppreference.com. See Syntax section.
Also the rvalue article, which reads
An rvalue may be used to initialize a const lvalue reference, in which case the lifetime of the object identified by the rvalue is extended until the scope of the reference ends.
P.S. You can use move semantics (C++11), too, which accept rvalues only. It's not hard to write a move constructor like this:
Test(Test&& obj) ...
Your copy constructor allows the object being copied to be modified.
The statement
Test t2 = func(t1);
will store the return value of func() in a temporary, and then copy that into t2. However, that requires a copy constructor that accepts a const reference, since a temporary cannot be bound to a non-const reference.
(Technically, the compiler is allowed to elide the temporary, but it is still required to issue diagnostics for your code assuming it has created the temporary. In other words, the copy constructor must be const).
Change your copy constructor to accept a const reference.
Test(Test const &obj) {
#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.
Suppose I have a class A. I have defined a copy constructor and an assignment operator overloading function. When I do
Class A;
Class B=A;
Then while defining Class B, is the copy constructor invoked or the assignment operator?
Thanks in advance.
EDIT:
Sorry, I mentioned wrong code. It should be:
A a;
A b=a;
IIRC T t = value invokes the copy constructor, you can verify that by outputting a string in the constructors to determine which method is used. IIRC when the declaration and assignment are on the same line, it is not called assignment but initialization.
On the other hand, what you've posted does not make sense, you cannot assign one type to another type, you can only assign to type instances.
EDIT: Even if you have a case of two different types (the context of your question is not clear on this one):
class A {};
class B {
public:
B(const A& other) { cout << "copy"; }
B& operator=(const A& other) { cout << "assign"; }
};
int main() {
A a;
B b = a; // copy con
B b1(a); // same as above
b = a; // assign op
}
Even then, when both the "copy constructor" and assignment operators take in another type, the copy constructor will still be invoked rather than the assignment operator.
Assuming you actually mean something like:
A a;
A b = a;
The copy constructor is invoked. The Standard allows = this special meaning in this usage.
Create a simple class with both, and debug what function is executed by setting a breakpoint in both. Then youll see, and youll also learn a little bit of debugging.
Let's try it out!
#include <iostream>
class A {
public:
A() {
std::cout << "default constructor\n";
}
A(const A& other) {
std::cout << "copy constructor\n";
}
A& operator=(const A& rhs) {
std::cout << "assignment operator\n";
return *this;
}
};
int main(int argc, char** argv) {
std::cout << "first declaration: ";
A a;
std::cout << "second declaration: ";
A b(a);
std::cout << "third declaration: ";
A c = a;
std::cout << "fourth declaration: ";
A d;
std::cout << "copying? ";
d = a;
return 0;
}
This prints:
first declaration: default constructor
second declaration: copy constructor
third declaration: copy constructor
fourth declaration: default constructor
copying? assignment operator
Working example here: http://codepad.org/DNCpqK2E
when you are defining a new object with assigning another object into it. It invokes copy constructor.
e.g,
Copy constructor call:
Class A;
Class B=A;
Assignment operator call:
Class A;
Class B;
B=A;
You can always test this, by writing a "print" statement in both the methods to find out which one is being called.
Hope it helped...
I want to enforce explicit conversion between structs kind of like native types:
int i1;
i1 = some_float; // this generates a warning
i1 = int(some_float): // this is OK
int i3 = some_float; // this generates a warning
I thought to use an assignment operator and copy constructor to do the same thing, but the behavior is different:
Struct s1;
s1 = other_struct; // this calls the assignment operator which generates my warning
s1 = Struct(other_struct) // this calls the copy constructor to generate a new Struct and then passes that new instance to s1's assignment operator
Struct s3 = other_struct; // this calls the COPY CONSTRUCTOR and succeeds with no warning
Are there any tricks to get that third case Struct s3 = other_struct; construct s3 with the default constructor and then call the assignment operator?
This all compiles and runs as it should. The default behavior of C++ is to call the copy constructor instead of the assignment operator when you create a new instance and call the copy constructor at once, (i.e. MyStruct s = other_struct;becomes MyStruct s(other_struct); not MyStruct s; s = other_struct;. I'm just wondering if there are any tricks to get around that.
EDIT: The "explicit" keyword is just what I needed!
class foo {
foo(const foo& f) { ... }
explicit foo(const bar& b) { ... }
foo& operator =(const foo& f) { ... }
};
foo f;
bar b;
foo f2 = f; // this works
foo f3 = b; // this doesn't, thanks to the explicit keyword!
foo f4 = foo(b); // this works - you're forced to do an "explicit conversion"
Disclaimer: I'm ready to take the downvotes on this, since this doesn't answer the question. But this could be useful to the OP.
I think it is a very bad idea to think of the copy constructor as default construction + assignment. It is the other way around:
struct some_struct
{
some_struct(); // If you want a default constructor, fine
some_struct(some_struct const&); // Implement it in the most natural way
some_struct(foo const&); // Implement it in the most natural way
void swap(some_struct&) throw(); // Implement it in the most efficient way
// Google "copy and swap idiom" for this one
some_struct& operator=(some_struct x) { x.swap(*this); return *this; }
// Same idea
some_struct& operator=(foo const& x)
{
some_struct tmp(x);
tmp.swap(*this);
return *this;
}
};
Implementing things that way is fool proof, and is the best you can obtain in term of conversion semantics in C++, so it is the way to go here.
You can get around this if you overload the type cast operator for other_struct, and edit the original structure accordingly. That said, it's extremely messy and there generally isn't a good reason to do so.
#include <iostream>
using namespace std;
struct bar;
struct foo {
explicit foo() {
cout << "In foo default constructor." << endl;
}
explicit foo(bar const &) {
cout << "In foo 'bar' contructor." << endl;
}
foo(foo const &) {
cout << "In foo constructor." << endl;
}
foo const & operator=(bar const &) {
cout << "In foo = operator." << endl;
return *this;
}
};
struct bar {
operator foo() {
cout << "In bar cast overload." << endl;
foo x;
x = *this;
return x;
}
};
int main() {
bar b;
foo f = b;
return 0;
}
Outputs:
In bar cast overload.
In foo default constructor.
In foo = operator.
In foo constructor.
In foo constructor.
In short, no.
The long version...actually that's about it. That's just not how it works. Had to come up with something to fill the character requirement though.
I don't think so. When you write
Struct s3 = other_struct;
It looks like an assignment, but really it's just declarative syntax that calls a constructor.