std::move 是否需要使用 co_yield 移动?
Is std::move required to move using co_yield?
假设我有一个在循环体中声明的 std::vector
并且 co_yield
ed:
some_generator<std::vector<int>> vector_sequence() {
while (condition()) {
std::vector<int> result = get_a_vector();
result.push_back(1);
co_yield std::move(result); // or just: co_yield result;
}
}
很明显,result
在被 co_yield
ed 之后不会再被使用(或者我大错特错),所以移动它是有意义的。我尝试了 co_yield
一个没有 std::move
的简单不可复制类型,但它没有编译,所以在通用代码中,人们会使用 std::move
。编译器是否无法识别这个(编译器错误?),或者 co_yield
总是复制左值的语言是故意的,所以我必须 std::move
?我知道 return
对作为局部变量的左值进行移动或某种其他类型的复制省略,这似乎与它没有太大区别。
我已阅读, which is related to this question, but does not answer it, and considered ,据我了解,与此问题无关。
隐式移动规则 ([class.copy.elision]/3) 适用于 return
和 co_return
语句以及 throw
表达式。它不适用于 co_yield
.
原因是,在[class.copy.elision]/3中列举的上下文中,return
或co_return
语句或throw
表达式的执行确保了隐式可移动实体的生命周期结束。例如,
auto foo() {
std::string s = ...;
if (bar()) {
return s;
}
// return something else
}
这里,即使在return
语句之后有代码,也保证如果 return
语句执行,那么下面的任何代码可以看到s
不会执行。这使得隐式移动 s
.
变得安全
相比之下,co_yield
只是挂起协程,并没有结束协程co_return
].因此,一般来说,在评估 co_yield result;
之后,协程可能稍后会恢复并再次使用完全相同的 result
变量。这意味着一般来说,将复制隐式转换为移动是不安全的;因此,该标准并未规定此类行为。如果你要搬家,写std::move
.
如果语言在你的例子中允许隐式移动,它必须有特定的规则来确保,虽然变量 可以 在 [=14= 之后再次使用】,其实不然。在您的情况下,循环可能确实会立即结束,因此 result
变量的生命周期将在再次观察到其值之前结束,但通常您必须指定一组条件,在这些条件下可以保证是这样。然后,您可以建议仅在这些条件下才会发生隐式移动。
假设我有一个在循环体中声明的 std::vector
并且 co_yield
ed:
some_generator<std::vector<int>> vector_sequence() {
while (condition()) {
std::vector<int> result = get_a_vector();
result.push_back(1);
co_yield std::move(result); // or just: co_yield result;
}
}
很明显,result
在被 co_yield
ed 之后不会再被使用(或者我大错特错),所以移动它是有意义的。我尝试了 co_yield
一个没有 std::move
的简单不可复制类型,但它没有编译,所以在通用代码中,人们会使用 std::move
。编译器是否无法识别这个(编译器错误?),或者 co_yield
总是复制左值的语言是故意的,所以我必须 std::move
?我知道 return
对作为局部变量的左值进行移动或某种其他类型的复制省略,这似乎与它没有太大区别。
我已阅读
隐式移动规则 ([class.copy.elision]/3) 适用于 return
和 co_return
语句以及 throw
表达式。它不适用于 co_yield
.
原因是,在[class.copy.elision]/3中列举的上下文中,return
或co_return
语句或throw
表达式的执行确保了隐式可移动实体的生命周期结束。例如,
auto foo() {
std::string s = ...;
if (bar()) {
return s;
}
// return something else
}
这里,即使在return
语句之后有代码,也保证如果 return
语句执行,那么下面的任何代码可以看到s
不会执行。这使得隐式移动 s
.
相比之下,co_yield
只是挂起协程,并没有结束协程co_return
].因此,一般来说,在评估 co_yield result;
之后,协程可能稍后会恢复并再次使用完全相同的 result
变量。这意味着一般来说,将复制隐式转换为移动是不安全的;因此,该标准并未规定此类行为。如果你要搬家,写std::move
.
如果语言在你的例子中允许隐式移动,它必须有特定的规则来确保,虽然变量 可以 在 [=14= 之后再次使用】,其实不然。在您的情况下,循环可能确实会立即结束,因此 result
变量的生命周期将在再次观察到其值之前结束,但通常您必须指定一组条件,在这些条件下可以保证是这样。然后,您可以建议仅在这些条件下才会发生隐式移动。