This question already has answers here:
What are copy elision and return value optimization?
(5 answers)
Closed 7 years ago.
I am trying to understand the concept of copy constructors in C++. I have written the following program:
#include<iostream>
using namespace std;
class Box{
private:
int d;
public:
Box(int i){
cout << "Constructor" << endl;
d = i;
}
Box(const Box &old){
cout << "Copy Constructor" << endl;
d = old.d;
}
int getd(){
return d;
}
~Box(){
cout << "Destructor" << endl;
}
Box operator+(const Box& op){
Box c(15);
c.d = d + op.d;
return c;
}
};
int main(){
Box a(10);
Box b = a;
Box c = a+b;
cout << c.getd() << endl;
return 0;
}
The output of this program is as follows:
Constructor
Copy Constructor
Constructor
20
Destructor
Destructor
Destructor
I don't understand why the copy constructor isn't getting called for the third line in the main function. I think that there should be a call to the copy constructor as operator+ function returns by value.
The compiler is optimising out the copy constructor call here, because the standard explicitly allows that copy to be "elided". What would be the point in such a copy, really?
You're absolutely right though, in that it's an opportunity for invocation of the copy constructor, and the compiler could do it. In fact, the standard does require that invoking the copy constructor be valid here.
Related
This question already has answers here:
What are copy elision and return value optimization?
(5 answers)
Closed 7 years ago.
#include <iostream>
using namespace std;
template <typename T> class tt
{
public :
int data;
tt()
{
std::cout << std::endl << " CONSTRUCTOR" << std::endl;
}
tt(const tt & that)
{
std::cout << std::endl << " COPY CONSTRUCTOR" << std::endl;
}
};
tt<int> test(void)
{
std::cout << std::endl << " INSIDE " << std::endl; tt<int> a; a.data =10 ;return a;
}
int main() {
// your code goes her
//tt<int> b;
tt<int> a =test();
cout<<a.data; //so that return value optimisation doesn't take place
return 0;
}
Why is the copy constructor not getting called in this case?
It gets called in the following case though
tt<int> b;
tt<int> a =b;
code link : http://ideone.com/e9lq3C
edit : This is not duplicate of What are copy elision and return value optimization?, because returned value is being referenced inside code.
a does not have a different location to the temporary. That is what copy elision and return value optimization do... they make it so that you don't get a temporary. Where you say a in test(), the optimization means you are referring to the same location as a in main. So no copy is required.
This is all due to compiler optimization (at least RVO). Compilers ends up creating one and only one object her (the one you asked to be created locally in test() becomes the same object as your a variable).
This question already has answers here:
What are copy elision and return value optimization?
(5 answers)
Closed 7 years ago.
I wrote this:
#include <iostream>
struct A
{
int a;
int b;
A() : a(10) { std::cout << "default ctor" << std::endl;}
~A(){ }
A(const A&){ std::cout << "copy ctor" << std::endl; }
A(const A&&){ std::cout << "move ctor" << std::endl; }
};
A init()
{
A a;
a.b = 20;
return a;
}
int main()
{
A a = init();
std::cout << a.b << std::endl;
}
I expected that A a = init() imposes the move-contructor call, but the outpur is:
default ctor
20
DEMO
The line
A a = init();
is inlined by NRVO. It creates an object by using it's default constructor in its segment of code:
A a;
Your move constructor will not be used here.
The move constructor here can be used with -fno-elide-constructors compiler flag. I've modified your example to compile it with this flag. But note, that default constructor will always be called because NRVO does not affect this in your code. NRVO only means that the object will be constructed in the storage that it is needed (not on the stack of your init method) so it would not be moved or copied. With the no-elide flag it can't be created there so it would be copied/moved there.
This question already has answers here:
Why copy constructor is not called here?
(2 answers)
Closed 8 years ago.
I have the following code:
#include <iostream>
using namespace std;
class X
{
public:
int g;
X() { cout << "constr" << endl; }
X(const X& ref1) { cout << "copy constr" << endl; }
};
X f()
{
X ee;
ee.g = 1;
return ee;
}
int main()
{
X ff = f();
return 0;
}
Running the code I see that the constructor was called only once and the copy constructor was never called. Don't you expect two constructor and one copy constructor calls here? Thanks!
This is a special case of the copy elision called return value optimization (the link explains precisely your case).
Copy Elision is an optimization implemented by many compilers to prevent extra, unnecessary, copies. Makes the return-by-value or pass-by-value possible in practice.
Take a look at the example in the following answer: https://stackoverflow.com/a/12953129/1938163
struct C {
C() {}
C(const C&) { std::cout << "A copy was made.\n"; }
};
C f() {
return C();
}
int main() {
std::cout << "Hello World!\n";
C obj = f();
}
(http://en.wikipedia.org/wiki/Return_value_optimization#Summary)
Perhaps incredible to believe the first time, depending on the compiler & settings, the following outputs are all valid:
Hello World!
A copy was made.
A copy was made.
Hello World!
A copy was made.
Hello World!
In your case, this is a special copy elision optimization called RVO - Return Value Optimization where an object returned by value from a method has its copy elided.
This question already has answers here:
Why is the destructor of the class called twice?
(5 answers)
Closed 9 years ago.
#include <iostream>
using namespace std;
class A
{
public:
A() { cout << "A's constructor" << endl; }
~A() { cout << "A's destructor" << endl; }
};
class B
{
public:
operator A() const { return A(); }
};
void f(A q) {}
int main()
{
B d1;
f(d1);
return 0;
}
Here's what I expected the code to do before I ran it:
The call to f results in a call to the converter function in class B which returns a temporary object. q's constructor gets called and when f exits, q's destructor gets called. I expected the following output:
A's constructor
A's destructor
but the output I got was:
A's constructor
A's destructor
A's destructor
Since there's another destructor, an extra object must have been created somewhere. Can someone explain what's happening here?
Use this as your class A:
class A
{
public:
A() { cout << "A's constructor: " << this << endl; }
A(const A& a) { cout << "A's copy constructor: " <<this << " form " << &a << endl; }
A(A&& a) { cout << "A's move constructor: " <<this << " form " << &a << endl; }
A& operator=(const A& a) { cout << "A's assignment" <<this << " form " << &a << endl; }
~A() { cout << "A's destructor: "<< this << endl; }
};
And you'll see why.
The question has been asked many times before, but since it is so generic it is difficult to find the older posts.
You are passing your objects around by value, meaning that the copies are created by copy constructor. Copy constructor is what created that "extra object" in your case. Meanwhile, you do not output anything from the copy constructor and therefore don't see the calls.
You have to add a debug output to your copy-constructor as well. That way you will see what is actually constructed and when.
There's potential for there to be 3 A objects constructed here. First is the temporary object created by A() in the conversion operator. Then, since the return type of the conversion operator is A, that temporary is copied into the return value. Then the return value of the conversion is copied into the parameter q of f.
To copy an object, the copy constructor is invoked. The default constructor will not be invoked, so you won't see the "A's constructor" message being printed.
It just so happens that the compiler elides one of these copies so that you only actually have one copy occur. Which one is being elided, I can't tell you (but it's probably the copy into the return value).
I think first destructor call for temporary object and second destructor for object which is constructed by move semantic.
I run this code for experimenting copy constructor and assignment operator
class AClass {
private:
int a;
public:
AClass (int a_) : a(a_) {
cout << " constructor AClass(int) " << a << endl;
}
AClass(const AClass & x) : a(x.a) {
cout << " copy constructor AClass(const AClass &) " << a << endl;
}
AClass & operator=(const AClass & x) {
a = x.a;
cout << " AClass& operator=(const AClass &) " << a - endl;
return *this;
}
};
AClass g () {
AClass x(8);
return x;
}
int main () {
cout << " before AClass b = g() " << endl;
AClass b = g();
cout << " after" << endl;
cout << " before AClass c(g()) " << endl;
AClass c (g());
cout << " after" << endl;
}
and found that no message appears for the return x;
Why?
Should not the copy constructor or operator= be called?
This is the output:
before AClass b = g()
constructor AClass(int) 8
after
before AClass c(g())
constructor AClass(int) 8
after
The compiler is allowed to elide copying in a case like this. This is called Return Value Optimization.
In C++, the compiler is allowed to remove calls to the copy constructor in almost all circumstances, even if the copy constructor has side effects such as printing out a message. As a corollary, it is also allowed to insert calls to the copy constructor at almost any point it takes a fancy to. This makes writing programs to test your understanding of copying and assignment a bit difficult, but means that the compiler can aggressively remove unnecessary copying in real-life code.
This is known as "return value optimisation". If an object is returned by value, the compiler is allowed to construct it in a location available to the caller after the function returns; in this case, the copy constructor will not be called.
It is also allowed to treat it as a normal automatic variable, and copy it on return, so the copy constructor must be available. Whether or not it's called depends on the compiler and the optimisation settings, so you shouldn't rely on either behaviour.
This is called Copy Ellision. The compiler is allowed to ellide copies in virtually any situation. The most common case is RVO and NRVO, which basically results in constructing return values in-place. I'll demonstrate the transformation.
void g (char* memory) {
new (memory) AClass(8);
}
int main () {
char __hidden__variable[sizeof(AClass)];
g(__hidden__variable);
AClass& b = *(AClass*)&__hidden__variable[0];
cout -- " after" -- endl;
// The same process occurs for c.
}
The code has the same effect, but now only one instance of AClass exists.
The compiler may have optimized away the copy constructor call. Basically, it moves the object.
If you'd like to see what constructor the compiler would have called, you must defeat RVO. Replace your g() function thus:
int i;
AClass g () {
if(i) {
AClass x(8);
return x;
} else {
AClass x(9);
return x;
}
}