Imagine:
S f(S a) {
return a;
}
为什么不允许别名a
和返回值槽?
S s = f(t);
S s = t; // can't generally transform it to this :(
如果以下情况的复制构造函数,规范不允许进行此转换:S
有副作用。相反,它至少需要两份副本(一份来自t
to a
,以及一个来自a
到返回值,另一个从返回值到s
,并且只有最后一个可以被省略。请注意,我写了= t
以上代表副本的事实t
to f's a
,在移动/复制构造函数存在副作用的情况下仍然是强制性的唯一副本)。
这是为什么?
这就是为什么复制省略对于参数没有意义。这实际上是关于在编译器级别实现这个概念的。
复制省略本质上是通过就地构造返回值来工作的。该值不会被复制出来;它是直接在其预期目的地创建的。调用者为预期输出提供了空间,因此最终是调用者提供了省略的可能性。
为了消除副本,函数内部需要做的就是在调用者提供的位置构造输出。如果该函数可以做到这一点,您就会得到复制省略。如果函数不能,那么它将使用一个或多个临时变量来存储中间结果,然后将其复制/移动到调用者提供的位置。它仍然是就地构建的,但输出的构建是通过复制进行的。
因此,特定函数之外的世界不必知道或关心函数是否进行省略。具体来说,caller函数的调用者不必知道函数是如何实现的。它没有做任何不同的事情;函数本身决定是否可以省略。
值参数的存储也由调用者提供。你打电话时f(t)
,是调用者创建了副本t
并将其传递给f
。同样,如果S
可以隐式构造自int
, then f(5)
将构建一个S
从 5 开始并将其传递给f
.
这一切都是由caller。被调用者不知道也不关心它是一个变量还是一个临时变量;它只是给出了一个堆栈内存(或寄存器或其他)。
现在记住:复制省略之所以有效,是因为被调用的函数将变量直接构造到输出位置。因此,如果您尝试忽略值参数的返回,则值参数的存储也必须是输出存储本身。但请记住:这是caller它为参数和输出提供存储。因此,要删除输出副本,caller必须直接将参数构造到output.
为此,现在调用者需要知道它所调用的函数将忽略返回值,因为如果要返回参数,它只能将参数直接粘贴到输出中。这在编译器级别通常是不可能的,因为调用者不一定具有该函数的实现。如果函数是内联的,那么也许它可以工作。但除此之外没有。
因此,C++委员会并没有考虑到这种可能性。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)