This question already has answers here:
Strange behavior of copy-initialization, doesn't call the copy-constructor!
(6 answers)
Copy constructor not calling
(2 answers)
Closed 2 years ago.
#include <iostream>
class Test {
public:
Test(const int& i)
{
std::cout << "Direct" << std::endl;
}
Test(const Test& t)
{
std::cout << "Copy" << std::endl;
}
};
int main()
{
Test test = 1;
return 0;
}
This program(compiled in C++11) will only output Direct, but the Test test = 1; means implicit convert 1 to a Test and then copy the result to test, I expected it output both of Direct and Copy, could anyone explain it?
Until c++17, this initialization:
Test test = 1;
will create a temporary Test from the int 1, and then the copy constructor is invoked for test. In practice, compilers will do copy-elision, and the temporary will be elided. You can force the compiler to not do the elision by passing the -fno-elide-constructors flag, to see both constructor calls.
From c++17, the wording is changed, and there is simply no temporary on the right hand side, so there is nothing to elide, and only one constructor is called. So even if you use -fno-elide-constructors, you will only see a single constructor call.
Related
This question already has answers here:
What are copy elision and return value optimization?
(5 answers)
Closed 5 years ago.
I was testing my knowledge in C++ and have encountered a problem. Consider this code:
class A
{
public:
A(int n = 0)
: m_n(n)
{
std::cout << 'd';
}
A(const A& a)
: m_n(a.m_n)
{
std::cout << 'c';
}
A(A&& a){
std::cout<<'r';
}
private:
int m_n;
};
int main()
{
A a = A();
std::cout << std::endl;
return 0;
}
Clearly, the A() constructor is an rvalue, as no permanent object has been created. So I think that first I have to see "d" as output. Then we are copying the rvalue to our new object, which is yet to be initialised. I have implemented a copy constructor that accepts an rvalue as an argument but I did not see the proof (no "r" output).
Can someone explain why that is?
You're seeing a form of copy elision -- the compiler is actually required to optimize and implement A a = A() by initializing a directly with the arguments to the constructor expression (() in this case) rather than creating a temporary and copying it into a. If you want to enforce an unnamed object to be copied, you need to initialize a with an expression that is not a simple constructor call.
Note that even then, the compiler may elide construtor calls by the as-if rule (if the only visible side effects are in the copy/move constructors/destructors. Your best bet to "force" a call to the move ctor is to use a named value and std::move:
A a1;
A a2 = std::move(a1);
This question already has answers here:
What are copy elision and return value optimization?
(5 answers)
Copy constructor not called?
(2 answers)
Closed 6 years ago.
As per my understanding, the move constructor will be called when there is a temporary object created. Here the getA() function is returning a temporary object but my program is not printing the message from the move constructor:
#include <iostream>
using namespace std;
class A
{
public:
A()
{
cout<<"Hi from default\n";
}
A(A && obj)
{
cout<<"Hi from move\n";
}
};
A getA()
{
A obj;
cout<<"from getA\n";
return obj;
}
int main()
{
A b(getA());
return 0;
}
The compiler is allowed to optimise out the instance obj and send the object directly back to the caller without a conceptual value copy being taken.
This is called named return value optimisation (NRVO). It's a more aggressive optimisation than classical return value optimisation (RVO) that a compiler can invoke to obviate the value copy of an anonymous temporary.
For the avoidance of doubt the compiler can do this even if there is a side-effect in doing so (in your case the lack of console output).
This question already has answers here:
Why is the copy constructor not called?
(4 answers)
Closed 9 years ago.
I have an understanding that copy constructor will be called when an object is created from an already existing object and also when a function returns object by value. So why in the below code the copy constructor is not called but the default constructor?
class A {
public:
A() { cout << "A" << endl; }
A(A &) { cout << "A&" << endl; }
A(const A &) { cout << "const A&" << endl; }
};
A fun() {
class A a;
return a;
}
int main() {
class A a = fun(); // output: A
}
Short answer: compiler optimizations.
First, the a object from your function is created directly in the scope of the main function, in order to avoid having to copy (or move in C++11) the local parameter out of the scope of the function via the function's return. This is return value optimization.
Then, in main, the statement becomes equivalent to class A a = A() and again the compiler is allowed to the create the a object in place, without copying from a temporary object. This is copy elision.
This is allowed even if the copy constructor (which is bypassed entirely) has side-effects, like in your example.
This question already has answers here:
What are copy elision and return value optimization?
(5 answers)
Closed 8 years ago.
There is a part of C++ code I don't really understand.
Also I don't know where should I go to search information about it, so I decided to ask a question.
#include <iostream>
#include <string>
using namespace std;
class Test
{
public:
Test();
Test(Test const & src);
Test& operator=(const Test& rhs);
Test test();
int x;
};
Test::Test()
{
cout << "Constructor has been called" << endl;
}
Test::Test(Test const & src)
{
cout << "Copy constructor has been called" << endl;
}
Test& Test::operator=(const Test& rhs)
{
cout << "Assignment operator" << endl;
}
Test Test::test()
{
return Test();
}
int main()
{
Test a;
Test b = a.test();
return 0;
}
Why the input I get is
Constructor has been called
Constructor has been called
?
a.test() creates a new instance by calling "Test()" so that's why the second message is displayed. But why no copy constructor or assignment called?
And if I change "return Test()" to "return *(new Test())" then the copy constructor is called.
So why isn't it called the first time?
Compilers are very smart. Both copies - returning from test and initialising b (not this is not an assignment) - are elided according to the following rule (C++11 ยง12.8):
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
Compilers are allowed to do this even if it would change the behaviour of your program (like removing your output messages). It's expected that you do not write copy/move constructors and assignment operators that have other side effects.
Note that is only one of four cases in which copy elision can occur (not counting the as-if rule).
The call to a.test() returns by value and this value is then assigned to b "copying" the return value. This invokes the copy constructor.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why copy constructor is not called in this case?
What are copy elision and return value optimization?
Can anybody explain to me why the following program yields output "cpy: 0" (at least when compiled with g++ 4.5.2):
#include<iostream>
struct A {
bool cpy;
A() : cpy (false) {
}
A (const A & a) : cpy (true) {
}
A (A && a) : cpy (true) {
};
};
A returnA () { return A (); }
int main() {
A a ( returnA () );
std::cerr << "cpy: " << a.cpy << "\n";
}
The question arised when I tried to figure out seemingly strange outcome of this example: move ctor of class with a constant data member or a reference member
The compiler is free to elide copy and move construction, even if these have side effects, for objects it creates on it own behalf. Temporary objects and return values are often directly constructed on the correct location, eliding copying or moving them. For return values you need to be a bit careful to have the elision kick in, though.
If you want to prevent copy elision, you basically need to have two candidate objects conditionally be returned:
bool flag(false);
A f() {
A a;
return flag? A(): a;
}
Assuming you don't change flag this will always create a copy of a (unless compilers got smarter since I last tried).