Why this move constructor is so greedy? - c++

I have the following code:
#include <iostream>
class foo_class {
std::string value;
public:
foo_class(const foo_class& v) : value{v.value} {
std::cout << "copy constructor" << std::endl;
}
foo_class(foo_class&& v) : value{std::move(v.value)} {
std::cout << "move constructor" << std::endl;
}
~foo_class() {
std::cout << "destructor" << std::endl;
}
foo_class(std::string v) : value{std::move(v)} {
std::cout << "type constructor" << std::endl;
}
};
struct Data {
foo_class a;
foo_class b;
};
int main() {
std::string c = "3";
Data x{c,c+"3"};
return 0;
}
IMPORTANT, I compile it with GCC and Clang (4.8.2 and 3.4 respectively) and the flag -fno-elide-constructors, so we don't elide the copy/move constructors.
The result of the execution is the following one:
type constructor
move constructor
destructor
type constructor
move constructor
destructor
destructor
destructor
Which means that the copy constructor is not being used at all, even when it should be used for the first argument of the constructor of the struct Data.
Next, If I delete the copy constructor, the code is still legal according to my compilers, but in my understanding should be illegal, cause I'm not casting to && (using std::move) when passing the first argument of the constructor of Data.
My question is simple:
Why is this happening?
Am I missing something?

Because the foo_class objects constructed in
Data x{c,c+"3"};
are both temporaries. So they invoke move constructor instead of copy constructor.
type constructor // 1. Construct a temporary foo_class object out of string "c" for a
move constructor // 2. Move the temporary object created above to x.a
destructor // 3. Destruct the temporary foo_class object created in 1
type constructor // 4. Same as 1, but the object is for b, and the string "33"
move constructor // 5. Same as 2, moved to x.b
destructor // 6. Destruct the temporary foo_class object created in 4
destructor // 7. Destruct x.b
destructor // 8. Destruct x.a

Related

Correctly move from a data member of a temporary object

Consider the following C++-Code
#include <iostream>
using namespace std;
struct WrapMe
{
WrapMe() { cout << "WrapMe Default Ctor of: " << this << endl; }
WrapMe(const WrapMe& other) { cout << "WrapMe Copy Ctor of " << this << " from " << &other << endl; }
WrapMe(WrapMe&& other) noexcept { cout << "WrapMe Move Ctor of " << this << " from " << &other << endl; }
~WrapMe() { cout << "Wrap Me Dtor of" << this << endl; }
};
struct Wrapper1
{
WrapMe& data()& { return member; }
WrapMe data()&& { return std::move(member); }
WrapMe member;
};
struct Wrapper2
{
WrapMe& data()& { return member; }
WrapMe&& data()&& { return std::move(member); }
WrapMe member;
};
int main()
{
auto wrapMe1 = Wrapper1().data();
auto wrapMe2 = Wrapper2().data();
}
with the output
WrapMe Default Ctor of: 00000092E7F2F8C4
WrapMe Move Ctor of 00000092E7F2F7C4 from 00000092E7F2F8C4
Wrap Me Dtor of00000092E7F2F8C4
WrapMe Default Ctor of: 00000092E7F2F8E4
WrapMe Move Ctor of 00000092E7F2F7E4 from 00000092E7F2F8E4
Wrap Me Dtor of00000092E7F2F8E4
[...]
Which is the correct way to move from the WrapMe member: Like Wrapper1 (return by value) or like Wrapper2 (return by rvalue-reference) does? Or are both ways equivalent here, as the ouput suggests? If not, why?
WrapMe&& data()&& { return std::move(member); }
This doesn't actually move anything. It just returns a rvalue reference to the member. For example I could do
auto&& wrapMe2 = Wrapper2().data();
and now wrapMe2 will be a dangling reference or
auto w = wrapper2();
auto&& wrapMe2 = std::move(x).data();
Now I have a reference to the member of w without w having changed at all.
Only because the move constructor of WrapMe is called to initialize the wrapMe2 object in the original line, a move operations actually takes place.
The version
WrapMe data()&& { return std::move(member); }
calls the move constructor already to construct the return value. The returned value will never refer to the original object or its member.
The line
auto wrapMe1 = Wrapper1().data();
then calls the move constructor again to initialize wrapMe1 from the return value of .data(). The compiler is however allowed to elide this second move constructor call and instead construct wrapMe1 directly from the expression in the return statement. This is why you see the same result.
With C++17 or later this elision would even be mandatory.
I don't know your use case, so I cannot be sure what the correct approach is, but just guessing on what you want to do:
For consistency between the two overloads, I would use the reference-returning version. Having data provide modifiable access to the member for lvalues, but not for rvalues, would be confusing.
However, you don't really need a member function to do this. Through data the caller has full control over the member anyway, so you could just make the member public from the start and then it could be used in the same way directly.

Copy constructor not called when initializing an object with return value of a function

Consider the following code:
#include <iostream>
using namespace std;
class A
{
public:
int a;
A(): a(5)
{
cout << "Constructor\n";
}
A(const A &b)
{
a = b.a;
cout << "Copy Constructor\n";
}
A fun(A a)
{
return a;
}
};
int main()
{
A a, c;
A b = a.fun(c);
return 0;
}
The output of the above code with g++ file.cpp is:
Constructor
Constructor
Copy Constructor
Copy Constructor
The output of the above code with g++ -fno-elide-constructors file.cpp is:
Constructor
Constructor
Copy Constructor
Copy Constructor
Copy Constructor
I know Return Value Optimization. My question is which call to copy constructor is elided(temporary object during returning or returned object being copied to b)?
If the elided copy constructor is the one used for creating b, then how is b created at all (because there is no constructor call in this case also)?
If I replace the line A b = a.fun(c); with a.fun(c) and compile using the first method or even the second method, then also the copy constructor is being called 2 times . So, if in the case explained in the previous paragraph, the temporary object's copy constructor is elided, then why isn't it elided in this case?
#include <iostream>
using namespace std;
class A
{
public:
int a;
A(): a(5)
{
cout << "Constructing: " << (void *)this << std::endl;
}
A(const A &b)
{
a = b.a;
cout << "Copy Constructor: " << (void *)this << " from " << (void *)&b << std::endl;
}
A fun(A a)
{
return a;
}
};
int main()
{
A a, c;
A b = a.fun(c);
std::cout << "a:" << (void *)&a << std::endl <<
"b:" << (void *)&b << std::endl <<
"c:" << (void *)&c << std::endl;
return 0;
}
Yields:
Constructing: 0x7fffbb377220
Constructing: 0x7fffbb377210
Copy Constructor: 0x7fffbb377230 from 0x7fffbb377210
Copy Constructor: 0x7fffbb377200 from 0x7fffbb377230
a:0x7fffbb377220
b:0x7fffbb377200
c:0x7fffbb377210
So it constructs a, constructs c, copies c to an intermediate (argument a of the function), and then copies the intermediate directly into b, skipping the typical copying of a to a return intermediate. This is even better demonstrated if you pass by value (change to A fun(const A& a):
Constructing: 0x7fff8e9642b0
Constructing: 0x7fff8e9642a0
Copy Constructor: 0x7fff8e964290 from 0x7fff8e9642a0
a:0x7fff8e9642b0
b:0x7fff8e964290
c:0x7fff8e9642a0
a is constructed, c is constructed, c is copied directly to b, despite b not being passed to fun!
The copy that is elided is the copy of the temporary return value into b. Without elision the return value is initialized from a and copied to b. Instead, the temporary that would otherwise hold the return value is constructed into b and initialized with a. [class.copy]/31:
when a temporary class object that has not been bound to a reference
(12.2) 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
You can observe this if you add an additional output in fun:
A fun(A a)
{
cout << "fun!" << endl;
return a;
}
Then with the elision you'll get
[…]
fun!
Copy Constructor
And without:
[…]
fun!
Copy Constructor
Copy Constructor

C++ Passing class by value

When i run the following program in XCode Version 5.1.1,
#include <iostream>
class MyClass
{
public:
MyClass() { std::cout << "MyClass Cons " << this << std::endl;}
~MyClass() { std::cout << "MyClass Dest " << this << std::endl;}
};
void Func(MyClass myClass)
{
}
int main(int argc, const char * argv[])
{
MyClass myClass1;
Func(myClass1);
return 0;
}
The output i get is
MyClass Cons 0x7fff5fbff918
MyClass Dest 0x7fff5fbff910
MyClass Dest 0x7fff5fbff918
Why is the destructor triggering twice and constructor only once?
The object is destroyed once, as you can see from the pointer values. You also see the destruction of another object. This object is a copy of the original.
By passing the object by value, the copy-constructor is invoked. Since this constructor does not print something, you do not see it in your output.
Add it to the class definition:
MyClass(const MyClass & other) { std::cout << "MyClass Copy-Cons " << this << " from " << &other << std::endl;}
And it should appear:
MyClass Cons 0x7fff1beee7ee
MyClass Copy-Cons 0x7fff1beee7ef from 0x7fff1beee7ee
MyClass Dest 0x7fff1beee7ef
MyClass Dest 0x7fff1beee7ee
The copy is created when you enter Func(). The copy is destroyed when it goes out of scope. This happens when you exit Func(). Finally, the original is destroyed when you exit the main() function.
The reason that you are seeing two destructor is because you are pass the arguments by value. Passing by value calls the copy constructor..
First Destructor:
At the end of the func function, the object goes out of scope, hence, it is destructed.
Second Destructor:
When the program end, the object is destructed.
My suggestion to remove the first destructor is to pass the object by reference rather than by value.
For example,
void Func(MyClass &myClass)
{
}
So now the output will have only:
MyClass Cons 0x7fff5fbff918
MyClass Dest 0x7fff5fbff918
Here the object is constructed twice(as everyone mentioned above). Hence 2 constructor + 2 destructor are called. The reason you are seeing 1 constructor is because you have NOT defined the Copy Constructor. CC is called when a copy is made for the pass-by-value operation.
add the copy constructor and then you can see both the constructor called.
Add Copy constructor - MyClass(const MyClass& obj) { std::cout << "MyClass Copy Cons " << this << std::endl;}

Why is copy-constructor not called in this case?

I encountered a code snippet and thought that it would call copy-constructor but in contrast , it simply called normal constructor . Below is the code
#include <iostream>
using namespace std;
class B
{
public:
B(const char* str = "\0")
{
cout << "Constructor called" << endl;
}
B(const B &b)
{
cout << "Copy constructor called" << endl;
}
};
int main()
{
B ob = "copy me";
return 0;
}
What you've discovered that B ob = "copy me"; notionally creates a B from the literal and then copy constructs ob, but that the compiler is allowed to elide the copy and construct directory into ob. g++ even elides the copy with no optimization enabled at all.
You can observe that this is the case by making your copy constructor private: The code will fail to compile even though the compiler won't actually use the copy constructor (the standard requires that copy constructors be accessible even when the call is elided).

How to force the compiler to use explicit copy constructor?

I wrote a small test program with a sample class containing also self-defined constructor, destructor, copy constructor and assignment operator. I was surprised when I realized that the copy constructor was not called at all, even though I implemented functions with return values of my class and lines like Object o1; Object o2(o1);
innerclass.hpp:
#include <iostream>
class OuterClass
{
public:
OuterClass()
{
std::cout << "OuterClass Constructor" << std::endl;
}
~OuterClass()
{
std::cout << "OuterClass Destructor" << std::endl;
}
OuterClass(const OuterClass & rhs)
{
std::cout << "OuterClass Copy" << std::endl;
}
OuterClass & operator=(const OuterClass & rhs)
{
std::cout << "OuterClass Assignment" << std::endl;
}
class InnerClass
{
public:
InnerClass() : m_int(0)
{
std::cout << "InnerClass Constructor" << std::endl;
}
InnerClass(const InnerClass & rhs) : m_int(rhs.m_int)
{
std::cout << "InnerClass Copy" << std::endl;
}
InnerClass & operator=(const InnerClass & rhs)
{
std::cout << "InnerClass Assignment" << std::endl;
m_int = rhs.m_int;
return *this;
}
~InnerClass()
{
std::cout << "InnerClass Destructor" << std::endl;
}
void sayHello()
{
std::cout << "Hello!" << std::endl;
}
private:
int m_int;
};
InnerClass innerClass()
{
InnerClass ic;
std::cout << "innerClass() method" << std::endl;
return ic;
}
};
innerclass.cpp:
#include "innerclass.hpp"
int main(void)
{
std::cout << std::endl << "1st try:" << std::endl;
OuterClass oc;
OuterClass oc2(oc);
oc.innerClass().sayHello();
std::cout << std::endl << "2nd try:" << std::endl;
OuterClass::InnerClass ic(oc.innerClass());
ic = oc.innerClass();
}
Output:
1st try:
OuterClass Constructor
OuterClass Copy
InnerClass Constructor
innerClass() method
Hello!
InnerClass Destructor
2nd try:
InnerClass Constructor
innerClass() method
InnerClass Constructor
innerClass() method
InnerClass Assignment
InnerClass Destructor
InnerClass Destructor
OuterClass Destructor
OuterClass Destructor
After some research I read that there is no guarantee that the compiler will use the explicitely defined copy constructor. I do not understand this behavior. Why does the copy constructor even exist then, if we do not know that it is called? How does the compiler decide if it uses it?
Or, even better, is there a way to force the compiler to use the self-defined copy constructor?
Just for completeness with the other answers, the standard allows the compiler to omit the copy constructor in certain situations (what other answers refer to as "Return Value Optimization" or "Named Return Value Optimization" - RVO/NRVO):
12.8 Copying class objects, paragraph 15 (C++98)
Whenever a temporary class object is copied using a copy constructor, and this object and the copy have the same cv-unqualified type, an implementation is permitted to treat the original and the copy as two different ways of referring to the same object and not perform a copy at all, even if the class copy constructor or destructor have side effects. For a function with a class return type, if the expression in the return statement is the name of a local object, and the cv-unqualified type of the local object is the same as the function return type, an implementation is permitted to omit creating the temporary object to hold the function return value, even if the class copy constructor or destructor has side effects. In these cases, the object is destroyed at the later of times when the original and the copy would have been destroyed without the optimization.
So in your innerClass() method, the copy constructor you might think would be called at the return is permitted to be optimized away:
InnerClass innerClass() {
InnerClass ic;
std::cout << "innerClass() method" << std::endl;
return ic; // this might not call copy ctor
}
I agree with Neil, you should not write a class which depends on the copy constructor being called. Namely because the compiler can do things like "Named Return Value Optimization" (link) which completely avoids the copy constructor in many return value scenarios. In order to enforce calling the copy constructor you'd need to write a lot of code aimed at "tricking" the C++ compiler. Not a good idea.
In a particular scenario though if you want to enforce calling the copy constructor, you can do an explicit call.
Object SomeFunc() {
Object o1 = ...
return Object(o1);
}
You should not design your class with a reliance on the copy constructor being called (or not called) in specific circumstances. The compiler is allowed to elide or add copy constructor calls at all sorts of places, and you really don't want to have to keep track of them.
As for why you need one - well, the compiler may decide it needs a copy, and the copy constructor is what it uses to do so. The advantage of copy constructor calls being elided is performance - copying is usually quite an expensive operation.
Is this the problem ?
OuterClass(const OuterClass & rhs)
{
std::cout << "OuterClass Constructor" << std::endl;
==>
std::cout << "OuterClass Copy Constructor" << std::endl;
}
OuterClass & operator=(const OuterClass & rhs)
{
std::cout << "OuterClass Constructor" << std::endl;
==>
std::cout << "OuterClass Assignment operator" << std::endl;
}
A copy paste error!
I would suggest you to debug the code once to see what exactly is happening. Debugging really helps you to find the problems.
EDIT: for inner class issue:
As others have already pointed out this is the case of The Name Return Value Optimization(NRVO).
InnerClass innerClass()
{
InnerClass ic;
std::cout << "innerClass() method" << std::endl;
return ic;
}
the compiler can transforms the function to
void innerClass( InnerClass &namedResult)
{
std::cout << "innerClass() method" << std::endl;
}
Thus it eliminates both the return by value of the class object and the need to invoke the class copy constructor.
Please go through below two links to understand more on NRVO:
MSDN NRVO
Stan Lippman's BLog
Object o1(); doesn't create any objects rather it defines a function prototype with function name o1, void arguments and return type as Object. You need to post some code to find the actual problem.
Post some code. I think you are using some incorrect syntax.
The copy constructor must exactly have the following signature:
MyObject(const MyObject&)
Then you can see if the copy constructor is called with the following code:
MyObject m1;
MyObject m2(m1);
You are not allowed to use MyObject m1(); that is a function declaration.