Open In App

Copy Elision in C++

Improve
Improve
Improve
Like Article
Like
Save Article
Save
Share
Report issue
Report

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 = func();
    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 if we used the “-fno-elide-constructors” flag which mandatorily calls copy constructor for GCC compiler.

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, it will be same as RVO. If the NRVO is enabled, then the call to the copy constructors will be elided. Otherwise, we may get the output similar to previous cases.

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 = "copy me";
    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 NRVO 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. For C++, it is guaranteed from C++ 17 standard.

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.



Last Updated : 05 Mar, 2024
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads