C++ 为什么不是';是否始终应用RVO/NRVO?

C++ 为什么不是';是否始终应用RVO/NRVO?,c++,C++,关于返回值优化机制的简要(可能是过时和过度简化的)总结如下: 实现可以在调用方的堆栈框架中创建隐藏对象,并将该对象的地址传递给函数。1991年前后,函数的返回值被复制到隐藏对象(…)中,Walter Bright发明了一种最小化复制的技术,有效地用用于保存结果的对象替换函数中的隐藏对象和命名对象[1] 因为这是一个讨论了很多的话题,所以我只链接我找到的最完整的 我的问题是,为什么不总是应用返回值优化?更具体地说(根据[1]中的定义),为什么每次函数调用都会发生这种替换,因为函数返回类型(因此堆栈

关于返回值优化机制的简要(可能是过时和过度简化的)总结如下:

实现可以在调用方的堆栈框架中创建隐藏对象,并将该对象的地址传递给函数。1991年前后,函数的返回值被复制到隐藏对象(…)中,Walter Bright发明了一种最小化复制的技术,有效地用用于保存结果的对象替换函数中的隐藏对象和命名对象[1]

因为这是一个讨论了很多的话题,所以我只链接我找到的最完整的


我的问题是,为什么不总是应用返回值优化?更具体地说(根据
[1]
中的定义),为什么每次函数调用都会发生这种替换,因为函数返回类型(因此堆栈上的大小)在编译时总是已知的,这似乎是一个非常有用的特性

在某些情况下,要求实现这样做可能是一种非优化,例如如果返回值被丢弃。如果您开始添加异常,那么就很难证明实现是正确的


相反,他们采用简单的方法,让实现决定何时进行优化,以及何时进行优化会适得其反。

显然,当通过值返回左值时,没有办法不进行复制。所以,让我们只考虑局部变量。应用于局部变量的一个简单原因是,通常不清楚要返回哪个对象。考虑这样的代码:

T f(Args... args) {
    T v1{some_init(args)};
    T v2{some_other(args)};
    bool rc = determine_result(v1, v2);
    return rc? v1: v2;
}
在局部变量
v1
v2
被创建时,编译器无法判断将返回哪一个,因此可以就地创建它


另一个原因是复制/移动构造和销毁可能会产生故意的副作用。因此,需要有抑制拷贝省略的方法。在介绍拷贝删除的时候,已经有很多C++代码,这些代码可能依赖于某些拷贝,即只有很少的情况才有资格复制Eclipse。还是我误解了你的问题?@πάνταῥεῖ 你的评论是正确的。我只是想了解“并非总是可以实现”背后的技术原因。从我在描述中读到的内容(显然,我从未参与过编译器的构造)来看,它是可行的,但通过阅读答案,我可以看到各种类型的原因阻止它无处不在:核心语言/值语义/程序逻辑/异常。。。我仍在试图对这些问题进行思考。有些编译器可能支持它,有些则不支持。仍然有很多不好的C++编译器实现(尤其是对于嵌入式领域中的特殊或更少的奇异CPU架构)。如果规范中说某些实现行为是可选的,那么编译器制造商可能会更广泛地接受这种行为,并让他们在满足新标准方面取得进展;否则返回v2完全允许RVO。当然,如果编译器可以确定
rc
的计算结果(例如,如果
determinate\u result
实际上既不查看
v1
也不查看
v2
,但由于某些编译时配置选项,它总是返回true),那么就可以假装您写了这篇文章,那么RVO仍然是可能的,甚至在这里也是允许的。@hvd:我认为在上述情况下不允许复制省略(不,你不会让我错误地称它为:-)!参见12.8[class.copy]第31段,该段仅当表达式为变量名(项目符号1)或返回临时对象(项目符号3)时,才允许对
return
语句进行复制省略。是的,没错,我已经编辑了我的注释,以涵盖以下内容:您可以满足RVO要求(别担心,我不是要你这么称呼它)将代码更改为使用
if
语句,在两个分支中使用两个独立的
return
语句。请注意,编译器需要在不执行复制省略时进行复制或移动!因为复制/移动或析构函数(复制/移动的对象)可能会有副作用它不能只是不做它!也就是说,复制省略总是做更少的工作。@DietmarKühl我想你可能有太多的nots。@t.C.:你是对的:我没有解释“can't”中的否定词……假设语句是使用
s/can/can/
(适当引用正则表达式…)。