在下面的示例中,NRVO (命名返回值优化)应用于每个这篇文章
std::string f1()
{
std::string str;
return str; // NVRO applies here!
}然而,考虑:
task<std::string> f2()
{
std::string str;
co_return str; // Does NVRO also apply here?
}发布于 2022-06-06 05:57:35
您所链接的文章所定义的NRVO (甚至不创建一个临时的)对协同不起作用,因为作品取决于用户提供的coroutine承诺类型:co_return语句中的表达式被输入到诺言的return_value方法中,后者可以决定如何处理它。
然而,有一个相关的优化仍然可能是有用的。[class.copy.elision]/3说:
隐式可移动实体是自动存储持续时间的变量,它要么是非易失性对象,要么是对非易失性对象类型的rvalue引用。在以下副本初始化上下文中,在尝试复制操作之前首先考虑移动操作:
首先执行重载解析,以选择要调用的副本或return_value重载的构造函数,就好像表达式或操作数是rvalue一样。如果第一次重载解析失败或未执行,则再次执行重载解析,将表达式或操作数视为lvalue。
这意味着,如果您从coroutine中按名称返回局部变量,它将被移动,而不是复制(只要允诺类型支持此操作)。例如,尽管不可能复制std::unique_ptr<int>,但clang仍然接受以下内容
// Assume a coroutine task type called Task<T> whose associated promise has a
// return_value(T) method. The co_return here will successfully call that
// method.
Task<std::unique_ptr<int>> MakeInt() {
auto result = std::make_unique<int>(17);
co_return result;
}因此,即使没有使用std::move,优化的“值被馈送到coroutine允诺作为rvalue引用”也适用。但是标准并没有说“甚至没有调用move构造函数”,也没有,因为这取决于如何处理它所给的表达式的承诺。
发布于 2020-05-18 13:07:14
我知道NRVO (名为返回值优化)是强制性的,因为C++17:
事实并非如此。NRVO仍然是一种优化。
未命名的返回值优化(RVO)是强制性的。
// NVRO在这里也有保障吗?
不,因为NRVO从来没有得到保证。
发布于 2020-05-18 13:25:56
为了完整起见,C++17中的保证省略只适用于直接从函数返回prvalue。返回命名变量只能在编译器喜欢的情况下接受省略。
至于您问题的实质,co_return值从来不受复制省略、保证或其他因素的影响。return关键字中返回值键的省略,并且coroutines不允许使用return。他们使用co_return,这是标准中的省略逻辑并不是。所以省略不适用。
之所以这样做,是因为合作机制是如何运作的。协同线是一个函数,其中包含一个承诺对象。这个允诺对象就是您如何将coroutine的co_return值(和其他状态)传递给coroutine函数返回的“未来”对象。
省略在正常函数中工作,因为调用约定要求调用方将返回值的存储传递给函数。因此,函数的实现可以选择只在该存储中构建对象,而不是构建单独的堆栈对象并将其复制到return上。
在合作机制中,回报值存在于承诺中,所以这是不可能的。
https://stackoverflow.com/questions/61870280
复制相似问题