10
votes

Consider the following code in C++:

struct A {A(int);};
A foo() {return static_cast<A>(0);}
A x = foo();

Here static_cast<A>(0) creates a temporary object by the standard [5.2.9-4], which is a prvalue. The standard [12.2-1] says

Temporaries of class type are created in various contexts: binding a reference to a prvalue (8.5.3), returning a prvalue (6.6.3), a conversion that creates a prvalue (4.1, 5.2.9, 5.2.11, 5.4), throwing an exception (15.1), entering a handler (15.3), and in some initializations (8.5).

So does the return statement will creates a temporary object again?

By the way, can anyone please tell me whether the standard guarantees an implicit type conversion will create an temporary object?

4
It is allowed to create a temporary, but probably will not. See Best way to return a class in C++Bo Persson

4 Answers

7
votes

(§4/6) mentions that

The effect of any implicit conversion is the same as performing the corresponding declaration and initialization and then using the temporary variable as the result of the conversion.

So yes, unless optimized, a temporary should be created, but I'm sure all modern compilers will perform a copy elision in your case. This particular optimization is called return value optimization (RVO). You can easilly test it by having constructors with side effects:

struct A {
    A(int){
        std::cout << "ctor";
    }
    A(const A & other)
    {
        std::cout << "copy ctor";
    }
    A(A&&other)
    {
        std::cout << "move ctor";
    }
};
5
votes

The temporary object will (most likely) be optimized away through Return-Value-Optimization (RVO) .

Example:

#include <iostream>
struct A
{
    A(int)
    {
        std::cout<< "A" << std::endl;
    }
    A(const A&)
    {
        std::cout << "A&" << std::endl;
    }
    A(A&&)
    {
        std::cout << "A&&" << std::endl;
    }
};
A foo() {return static_cast<A>(0);}

int main()
{
    A x = foo();
    return 0;
}

output: live example

A

output with RVO disabled: live example

A
A&&
A&&
4
votes

Short answer: No there will be only one creation of A in your code.

To achieve this, the compiler uses the (Named) Return value optimization that eliminates unnecessary object creation/copy upon returns. The more general case, Copy elision, that eliminates unnecessary copying of objects, will be use in plenty of related case.

You can play with GCC option -fno-elide-constructors to see the differences.

2
votes

The actual result in this particular case will depend on a particular compiler and optimization levels. In fact, a decent modern compiler with a good optimization level can completely remove any temporary object. Consider this:

#include <iostream>

using namespace std;

struct A {
    A(int) { cout << __PRETTY_FUNCTION__ << endl; }
    ~A() { cout << __PRETTY_FUNCTION__ << endl; }
};

inline
A foo() {
    return static_cast<A>(0);
};


int main(void) {
    A a = foo();
    cout << "hello world!" << endl;
}

gcc-5.1.1 with -O4 builds an executable which outputs literally this:

A::A(int)
hello world!
A::~A()