返回一个临时对象是否会在 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
来查看差异。
考虑以下 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
来查看差异。