Joh*_*itb 38 c++ return-value-optimization c++11
想像:
S f(S a) {
return a;
}
Run Code Online (Sandbox Code Playgroud)
为什么不允许别名a和返回值槽?
S s = f(t);
S s = t; // can't generally transform it to this :(
Run Code Online (Sandbox Code Playgroud)
如果复制构造函数S具有副作用,则规范不允许此转换.相反,它需要至少两个副本(一个来自t于a,一个来自a于返回值,另一个是返回值s,且只有最后一个可以省略.请注意,我写了= t上述表示的副本的事实的t到f的a,这仍然是在移动的副作用存在强制性的唯一拷贝/拷贝构造函数).
这是为什么?
Nic*_*las 20
这就是为什么copy elision对参数没有意义的原因.它实际上是关于编译器级别的概念的实现.
复制elision的工作原理是基本上构建返回值.该值不会被复制出来; 它直接在预定目的地创建.调用者为预期的输出提供空间,因此最终是调用者提供了省略的可能性.
函数内部需要做的所有操作都是为了忽略副本,而是在调用者提供的位置构造输出.如果函数可以执行此操作,则会获得copy elision.如果函数不能,则它将使用一个或多个临时变量来存储中间结果,然后将其复制/移动到调用者提供的位置.它仍然就地构建,但输出的构造通过复制发生.
因此,特定功能之外的世界不必知道或关心某个功能是否能够完成.具体而言,函数的调用者不必知道函数的实现方式.它没有做任何不同的事情; 它是功能本身决定是否可以省略.
调用者还提供值参数的存储.当您调用时f(t),调用者会创建副本t并将其传递给f.类似地,如果S是从a隐式构造的int,那么f(5)将从S5 构造一个并将其传递给f.
这一切都是由来电者完成的.被叫者不知道或不关心它是变量还是临时的; 它只是给出了一堆堆栈内存(或寄存器或其他).
现在记住:copy elision有效,因为被调用的函数将变量直接构造到输出位置.因此,如果您试图忽略值参数的返回,则value参数的存储也必须是输出存储本身.但请记住:调用者为参数和输出提供存储.因此,为了省略输出副本,调用者必须将参数直接构造到输出中.
要做到这一点,现在调用者需要知道它调用的函数将忽略返回值,因为如果返回参数,它只能将参数直接粘贴到输出中.这在编译器级别通常是不可能的,因为调用者不一定具有该函数的实现.如果函数是内联的,那么也许它可以工作.但否则没有.
因此,C++委员会并没有考虑这种可能性.
从 t 到 a 删除副本是不合理的。该参数被声明为可变的,因此需要进行复制,因为预计会在函数中对其进行修改。
从返回值我看不出任何复制的理由。也许这是某种疏忽?按值参数感觉就像函数体内的局部变量......我看不出有什么区别。