返回一个临时对象是否会在 C++ 中创建一个临时对象?

Does returning a temporary object create a temporary object in C++?

考虑以下 C++ 代码:

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

这里static_cast<A>(0)按照标准[5.2.9-4]创建了一个临时对象,是一个纯右值。标准 [12.2-1] 说

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).

那么return语句是否会再次创建一个临时对象?

顺便问一下,谁能告诉我标准是否保证隐式类型转换会创建一个临时对象?

此特定情况下的实际结果将取决于特定的编译器和优化级别。事实上,具有良好优化级别的体面的现代编译器可以完全删除任何临时对象。考虑一下:

#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;
}

带有 -O4 的 gcc-5.1.1 构建了一个可执行文件,其字面上输出如下:

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

临时对象将(很可能)通过 Return-Value-Optimization (RVO) 优化掉。

示例:

#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;
}

输出:live example

A

禁用 RVO 的输出:live example

A
A&&
A&&

(§4/6) 提到

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.

所以是的,除非优化,否则应该创建一个临时文件,但我相信所有现代编译器都会在您的情况下执行复制省略。这种特殊的优化称为 return value optimization (RVO)。您可以通过具有副作用的构造函数轻松测试它:

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

简答:不,您的代码中只会创建一个 A

为了实现这一点,编译器使用了 (Named) Return value optimization that eliminates unnecessary object creation/copy upon returns. The more general case, Copy elision,消除了不必要的对象复制,将在大量相关案例中使用。

您可以使用 GCC 选项 -fno-elide-constructors 来查看差异。