Neither copy nor move constructor called [duplicate] - c++

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).

Related

Different behaviour based on move constructor [duplicate]

This question already has an answer here:
Does the behavior of guaranteed copy elision depend on existence of user-defined copy constructor?
(1 answer)
Closed 1 year ago.
I have a piece of code to check if move happened.
struct Foo
{
Foo() = default;
Foo(Foo&& other) = default;
double a[1000];
double b[1000];
};
Foo giveMe()
{
Foo ret;
std::cout << &ret << std::endl;
return ret;
}
int main()
{
Foo o1 = giveMe();
std::cout << &o1 << std::endl;
return 0;
}
Well, it does not. The addresses of ret and o1 are, for instance, as follows:
008F7D78
008FBC08
However, after slight change in move constructor:
struct Foo
{
Foo() = default;
Foo(Foo&& other) {}
double a[1000];
double b[1000];
};
the addressees are the same:
010FBE28
010FBE28
What is happening here? I assume that this behaviour is somehow related to POD or trivial types but I am not sure how.
What is happening here?
Optimisation is happpening here. More precisely: Named Return Value Optimisation (NRVO).
Even though the abstract machine moves in both cases, NRVO optimised (elided) the move away from the second example.
The address check is there just to see if move or copy happened.
The class isn't copyable, so a copy can't have happened. Also, the address check cannot distinguish between copied and moved object. Either would have a different address.
To clarify a possible misconception: "Move" construction creates a new object using the move constructor. That new object typically has a different address than the object that was moved from, just like when copying. The only case where the address of the new object is the same is when the move is optimised away such that the constructor is never actually called (which can also be done with copies).

Copy constructor on return in C++ [duplicate]

This question already has answers here:
What are copy elision and return value optimization?
(5 answers)
Closed 2 years ago.
I'm trying to understand the following
#include <iostream>
class Number {
int _value;
public:
Number(int number) : _value(number) { std::cout<<"constructed!\n"; }
Number(const Number& other) : _value(other._value) { std::cout<<"copied!\n"; }
~Number() { std::cout<<"destructed!\n"; }
};
Number create_number(int value) {
Number out(value);
return out;
}
int main() {
Number my_number = create_number(10);
}
The output is
constructed!
destructed!
I would have expected that inside create_number an object would be constructed, copied to the output of the function and then destructed once the function returned.
Something like that seems to happen because if I make the copy constructor explicit
explicit Number(const Number& other) : _value(other._value) { std::cout<<"copied!\n"; }
the compiler yells on return out with no matching constructor for initialization of 'Number'. If I call the copy constructor within create_number explicitly or even cast the Number out to a Number (huh?)
return Number(out);
return (Number)out;
the compiler is happy and I get the expected output
constructed!
copied!
destructed!
destructed!
I feel like I'm missing something about return, copy constructors and/or (implicit) casting. Can someone explain this?
That's copy elision. Without getting too much into the C++ standard's obscure language, in most cases the compiler may elide (optimize away) the copy, but isn't required to. This is treated like any other optimization.
Interestingly, this is a rare exception to the as-if rule, where the side-effects of an optimization are observable - see the notes in these links.

Relationship between copy initialization and copy constructor [duplicate]

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.

Why does my rvalue copy constructor not work? [duplicate]

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);

Why is the move constructor not called? [duplicate]

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).