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



考虑C++中的以下代码:

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

这里static_cast<A>(0)根据标准[5.2.9-4]创建一个临时对象,它是一个prvalue。标准[12.2-1]规定

类类型的临时性是在各种上下文中创建的:绑定对prvalue的引用(8.5.3),返回prvalue(6.6.3),创建prvalue的转换(4.1、5.2.9、5.2.11、5.4),抛出异常(15.1),输入处理程序(15.3),以及在某些初始化中(8.5)

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

顺便说一句,有人能告诉我这个标准是否保证隐式类型转换会创建一个临时对象吗?

(§4/6)提到

任何隐式转换的效果都与执行相应的声明和初始化,然后使用临时变量作为转换的结果相同。

所以,是的,除非进行了优化,否则应该创建一个临时的,但我相信所有现代编译器都会在您的情况下执行副本省略。这种特殊的优化被称为返回值优化(RVO)。你可以通过让构造函数产生副作用来简单地测试它:

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

临时对象将(很可能)通过返回值优化(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;
}

输出:实例

A

RVO禁用时的输出:实例

A
A&&
A&&

简单回答:不,在您的代码中只有一个A的创建。

为了实现这一点,编译器使用(命名)返回值优化来消除返回时不必要的对象创建/复制。更普遍的情况是,复制省略,它消除了不必要的对象复制,将在许多相关的情况下使用。

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

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

#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()

最新更新