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.
Related
This question already has answers here:
Copy/Move Constructor is not called when storing result of overloaded operator+
(1 answer)
c++: MyClass x(1,2,3) vs MyClass x = MyClass(1,2,3)
(1 answer)
What's the difference between Radio r = Radio("PSR", 100.8) and Radio("PSR", 100.8)?
(1 answer)
Shouldn't there be a copy ctor invocation here? Elision disabled (no named return value optimization)
(1 answer)
Is there is a difference between two constructs
(1 answer)
Closed 7 months ago.
I defined a class with both copy and move constructors. The copy constructor seems to work fine but when I try to invoke the move constructor it doesn't work.
#include <iostream>
class A{
public:
A() = default;
A(A& a){
std::cout << "Copy constructor." << std::endl;
};
A(A&& a){
std::cout << "Move constructor." << std::endl;
};
};
int main(int argc, char *argv[]){
auto a = A(A());
std::cout << "here" << std::endl;
auto b = A(a);
return 0;
}
I expect the auto a = A(A()); should invoke move constructor because its input (A()) is an rvalue. But the output is this:
[amirreza#localhost tmp]$ ./a.out
here
Copy constructor.
Is my assumption wrong?
I'm using gcc version 10.3.1 without explicitly specifying the c++ version.
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:
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.
In the following code the line that creates nested object prints only "constructor" with gcc, but not with VS 2013:
#include <iostream>
using namespace std;
struct test {
test() { cout << "constructor" << endl; }
test(const test&) { cout << "copy constructor" << endl; }
test(test&&) { cout << "move constructor" << endl; }
~test() { cout << "destructor" << endl; }
};
struct nested {
test t;
// nested() {}
};
auto main() -> int {
// prints "constructor", "copy constructor" and "destructor"
auto n = nested{};
cout << endl;
return 0;
}
Output:
constructor
copy constructor
destructor
destructor
So I guess what happening here is that a temporary object gets copied into n. There is no compiler-generated move constructor, so that's why it's not a move.
I'd like to know if this is a bug or an acceptable behaviour? And why adding a default constructor prevents a copy here?
It's not auto that's the problem; the following will exhibit the same:
nested n = nested{};
The temporary is being direct-initialized with {}, and then n is being copy-initialized with that, because test is a class-type (in this case, has user-defined constructor).
An implementation is permitted to directly initialize the ultimate target (n), but isn't obligated to, so either is legal.
Lots (really, lots) of details in 8.5 and 8.5.1 of the Standard.
This is a failure of MSVC to do copy elision (I'd guess related to the brace-init-constructor). It's perfectly legal both ways.