Hi there!


This is a subject related to copy constructors and efficiency in C++. The following code snippet shows three functions: 'example1', 'example2' and 'example3'. I have been discussing with a workmate which one is the most efficient :


Code:

#include <iostream>
#include <string>


//just an example class
class MyClass
{
public:
    std::string toString()
    {
        return "just an example";
    }
};


static MyClass myObj;




bool example1()
{
    std::string str = myObj.toString();//executing copy constructor of std::string
    
    //... some code
    std::cout << str << std::endl;
    
    //.. some other code
    std::cout << str << std::endl;
    
    return true;
}


bool example2()
{
    const std::string& str = myObj.toString();//avoid copy constructor of std::string, but more verbose.
    
    //... some code
    std::cout << str << std::endl;
    
    //.. some other code
    std::cout << str << std::endl;
    
    return true;
}


bool example3()
{
    //avoid copy constructor of std::string, but we get two call stacks .
    
    //... some code
    std::cout << myObj.toString() << std::endl;
    
    //.. some other code
    std::cout << myObj.toString() << std::endl;
    
    return true;
}




int main()
{
    for (size_t i = 0; i < 1000000; i++)
    {
        //example1();
        example2();
        //example3();
    }
}

In my opinion, the less efficient one is 'example1' because it implies the execution of the copy constructor which, in turn, implies a system call to allocate memory and another call to free such memory. But my workmate says 'example1' is the most efficient one, because the compiler will perform an optimization to avoid the copy constructor.


What is your opinion about that?


My opinion is that efficiency issues should not be left to the compiler, they should always be fixed in the c++ code. The code is aimed to be run on all platforms (Windows, Linux and Mac) and different compilers may behave in a different way. Even different versions of the same compiler may or may not perform optimizations.




I would choose 'example2' or even 'example3' because a call stack will always be faster than a system call to allocate memory.


Here I used std::string as an example, but it can be with any user defined complex type.


Thanks a lot!