// version 1
MyObject Widget::GetSomething() {
return MyObject();
}
在C++ 03中这需要MyObject
通过copyable。在运行时,如果标准允许在此处使用elision,则不会使用具有合理设置的任何“真实”编译器进行复制。
在C++ 11或14中,它要求对象是可移动或可复制的。 Elision仍然存在;没有移动或复制完成。
在C++ 17中,没有任何移动或拷贝在这里可以退出。
在任何情况下,实际上,MyObject
都是直接在返回值中构造的。
// version 2
MyObject Widget::GetSomething() {
return std::move(MyObject());
}
这在C++ 03中无效。
在C++ 11及更高版本中,将MyObject
移入返回值中。此举必须在运行时发生(禁止如果消除)。
// version 3
MyObject Widget::GetSomething() {
auto obj = MyObject();
return obj;
}
与版本1相同,除了C++ 17的行为类似于C++ 11/14。另外,这里的elision更脆弱;看似无害的更改可能会迫使编译器实际移动obj
。在C++ 11/14/17中(以及C++ 03中的2个副本),理论上2个移动都被忽略了。第一个安全,第二个脆弱。
// version 4
MyObject Widget::GetSomething() {
auto obj = MyObject();
return std::move(obj);
}
在实践中,这种行为就像版本2的额外移动(复制在C++ 03)出现在构建obj
但它会被省略,所以什么也不会发生在运行时。
Elision允许消除复制/移动的副作用;对象的生命期被合并到一个对象中,并且移动/复制被消除。构造函数仍然存在,它从未被调用过。
答案
1和3都将编译为相同的运行时代码。 3稍微脆弱一些。
2和4都编译成相同的运行时代码。它不应该比1/3更快,但是如果编译器证明没有这样做可以消除这种情况,那么就和编译时一样 - 如果这样做,它可以编译成与1/3相同的运行时代码。这远远没有保证,而且非常脆弱。
所以1>=3>=2>=4
是在实践中更快到更慢的顺序,其中“更脆弱”的代码,否则是相同的速度是<=
。
这样情况的一个例子,可以使3比1更慢,如果你有一个if语句:
// version 3 - modified
MyObject Widget::GetSomething() {
auto obj = MyObject();
if (err()) return MyObject("err");
return obj;
}
突然许多编译器将被迫移动obj
到返回值,而不是eliding obj
和返回值一起。
“来自社区的广泛回应” - 例子?这在AFAIK的共识中是不好的。 –
你错过了我喜欢的那个:'return {};' –
“提供了最大的优化”本质上是一个特定于实现的问题 –