Given
struct Range{ Range(double from, double to) : from(from), to(to) {} double from; double to; }; struct Box{ Box(Range x, Range y) : x(x), y(y) {} Range x; Range y; };
suppose we run Box box(Range(0.0,1.0),Range(0.0,2.0))
.
Could a modern compiler with optimizations enabled avoid copying Range
objects altogether during this construction? (i.e. construct the Range
objects inside box
to begin with?)
Passing by value (rather than by reference) means a copy needs to be made. So passing by value into your copy constructor means you need to make a copy before the copy constructor is invoked, but to make a copy you first need to call the copy constructor. Save this answer.
Copy elision is the general process where, when returned from a function, an object is not copied nor moved, resulting in zero-copy pass-by-value semantics. It includes both return value optimization (RVO) and named return value optimization (NRVO).
pass-by-reference does not make any copy, it gets the reference of the object itself by just renaming it, so no any copying operation.
Copy elision is an optimization implemented by most compilers to prevent extra (potentially expensive) copies in certain situations. It makes returning by value or pass-by-value feasible in practice (restrictions apply).
There are actually two copies being performed on each Range
object passed to the constructor. The first happens when copying the temporary Range
object into the function parameter. This can be elided as per the reference given in 101010's answer. There are specific circumstances in which copy elision can be performed.
The second copy happens when copying the function parameter into the member (as specified in the constructor initialization list). This cannot be elided, and this is why you still see a single copy being made for each parameter in YSC's answer.
When the copy constructor has side-effects (such as the prints in YSC's answer), copy elision can still be performed for the first copy, but the second copy must remain.
However, the compiler is always free to make changes if they do not alter the observed behavior of the program (this is known as the "as-if" rule). This means that if the copy constructor has no side effects and removing the constructor call will not change the result, the compiler is free to remove even the second copy.
You can see this by analyzing the generated assembly. In this example, the compiler optimizes out not only the copies, but even the construction of the Box
object itself:
Box box(Range(a,b),Range(c,d)); std::cout << box.x.from;
Generates identical assembly as:
std::cout << a;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With