在您的示例中,我没有看到任何 (N)RVO。[class.copy]/31 中允许但不强制要求RVO 或复制/移动省略。这里有些例子:
#include <iostream>
struct A
{
A(int i) { std::cout << "ctor\n"; }
~A() { std::cout << "dtor\n"; }
A& operator=(A const&)
{ std::cout << "copy-assignment-op\n"; return *this; }
// N.B. no default move ctor will be created!
};
A foo() { return 42; }
A bar() { return A(42); }
const A cfoo() { return 42; }
const A cbar() { return A(42); }
int main()
{
std::cout << "A a(42);\n";
A a(42);
std::cout << "\na = foo();\n";
a = foo();
std::cout << "\na = bar();\n";
a = bar();
std::cout << "\nA b( foo() );\n";
A b( foo() );
std::cout << "\nA c( bar() );\n";
A c( bar() );
std::cout << "\nA d( cfoo() );\n";
A d( cfoo() );
std::cout << "\nA e( cbar() );\n";
A e( cbar() );
std::cout << "\ndtors following for a, b, c, d, e\n";
}
最新编译器的输出(许多甚至 at -O0
)是:
一个(42);
演员
a = foo();
演员
复制分配操作
dtor
一个 = 酒吧();
演员
复制分配操作
dtor
一个 b( foo() );
演员
一个 c(bar());
演员
一个 d( cfoo() );
演员
一个 e( cbar() );
演员
dtors 跟随 a, b, c, d, e
dtor
dtor
dtor
dtor
dtor
如您所见,返回类型是否const
不影响 RVO。但是,它可以,因为它不是强制性的。因此,如果您有一个旧的/奇怪的编译器 - 测试它(或在文档中查找)。
上例中有两种 RVO:
将具有自动存储持续时间的对象复制/移动到返回值(也称为 NRVO),例如
A foo() { A a; return a; }
[class.copy]/31 允许这个
在return
具有类返回类型的函数的语句中,当表达式是具有与函数返回类型相同的 cv 非限定类型的非易失性自动对象(函数或 catch 子句参数除外)的名称时
将临时的省略复制/移动到另一个对象
A a( foo() ); // only 1 ctor is called
A foo() { return A(); } // no copy/move from the temporary to the return value
这是允许的
当尚未绑定到引用 (12.2) 的临时类对象将被复制/移动到具有相同 cv 非限定类型的类对象时
const
其中“cv-unqualified”(可能)意味着这种优化忽略了顶级合格。