Copy Elision in C++
Copy elision (also known as copy omission) is a compiler optimization method that prevents objects from being duplicated or copied. It makes ‘returning by value’ or ‘pass-by-value’ feasible in practice. In simple terms, the compiler prevents the making of extra copies which results in saving space and better the program complexity(both time and space); Hence making the code more optimized. Nowadays, almost every compiler uses it.
This also means fewer objects can be created, so you also can’t rely on a specific number of destructors being called. Or we can conclude that the compiler gets some special power in which they can print according to their utmost feasibility.
Example:
C++
// C++ program to demonstrate the working of copy elision // via RVO #include <iostream> using namespace std; class GFG { public : GFG() { cout << "GeeksforGeeks" ; } GFG( const GFG&) // Copy Construcctor { cout << " GeeksforGeeks Copy Constructor" ; } }; GFG func() { return GFG(); // RVO example } int main() { GFG G; return 0; } |
Output:
GeeksforGeeks
Now it is on the compiler to decide what it wants to print, it could either print the above output or it could print case 1 or case 2 below, and this is what Return Value Optimization is. In simple words, RVO is a technique that gives the compiler some additional power to terminate the temporary object created which results in changing the observable behavior/characteristics of the final program.
Case 1:
GeeksforGeeks GeeksforGeeks Copy Constructor GeeksforGeeks Copy Constructor
Case 2:
GeeksforGeeks GeeksforGeeks Copy Constructor
These cases will appear because we used the “-fno-elide-constructors” flag which mandatorily calls copy constructor.
Example:
C++
// C++ program to demonstrate the working of copy elision // via NRVO #include <iostream> using namespace std; class GFG { public : GFG() { cout << "GeeksforGeeks" ; } GFG( const GFG&) // Copy Construcctor { cout << " GeeksforGeeks Copy Constructor" ; } }; GFG func() { GFG G; return G; // NRVO example } int main() { GFG G = func(); return 0; } |
Output:
GeeksforGeeks
In NRVO there won’t be any other cases as we explicitly called it the instance of an object which resulted in calling only once. So there won’t be a case of the “-fno-elide-constructors” flag now.
Example:
C++
// C++ program to demonstrate working of Copy Elision #include <iostream> using namespace std; class B { public : B( const char * str = "\0" ) // default constructor { cout << "Constructor called" << endl; } B( const B& b) // copy constructor { cout << "Copy constructor called" << endl; } }; int main() { B ob; return 0; } |
Output:
Constructor called
Why copy constructor is not called?
According to theory, when the object “ob” is being constructed, one argument constructor is used to convert “copy me” to a temporary object & that temporary object is copied to the object “ob”. So the statement
B ob = "copy me"; // Also RVO form to represent
should be broken down by the compiler as:
B ob = B("copy me"); // Also NRVO form to represent
However, most C++ compilers avoid such overheads of creating a temporary object & then copying it.
The modern compilers break down the statement B ob = "copy me"; //copy initialization as B ob("copy me"); //direct initialization and thus eliding call to copy constructor.
However, if we still want to ensure that the compiler doesn’t elide the call to copy constructor [disable the copy elision], we can compile the program using the “-fno-elide-constructors” option with C++
Output:
GEEKSFORGEEKS:~$ g++ copy_elision.cpp -fno-elide-constructors GEEKSFORGEEKS:~$ ./a.out /\---This is a flag which calls copy constructor statement and Constructor called reduce compiler's optimiziblity Copy constructor called
If the “-fno-elide-constructors” option is used, a first default constructor is called to create a temporary object, then the copy constructor is called to copy the temporary object to ob.
Difference Between NRO and RVO
NRVO |
RVO |
---|---|
It is known as Named Return Value Optimization | It is known as Return Value Optimization |
It is neither guaranteed nor mandatory to be called | It is guaranteed to be called in a modern compiler program |
Instead of creating a local return object and then moving/copying it in place of the function call, NRVO instantly creates it in the called place. |
Instead, the returned object is constructed in place of the function call. It does not allow the creation of a local object that is used as a return value. |
Please Login to comment...