struct test {
test& foo(std::vector<int> const& v) {
assert(v.size() == 1); return *this;
}
void bar(std::vector<int> v) {}
};
void do_test() {
std::vector<int> v = { 42 };
return test{}.foo(v).bar(std::move(v)); // <-- here
}clang在“这里”字符串上给出一个错误bugprone-use-after-move。
为什么它是在移动后使用?
发布于 2022-09-15 11:06:38
因为C++17保证函数调用中的后缀表达式,即在这里,在参数列表中的任何表达式之前对test{}.foo(v).bar进行求值。
因此,只有在foo返回之后,移动构造才会发生。
然而,在C++17之前,没有这样的保证,移动-建设可能发生在调用foo之前。
依赖这些新的担保是否是一个好主意是值得怀疑的。有些工具倾向于忽略它们,并继续警告这些代码,因为如果使用不同的-std=标志编译,这将是危险的。例如,GCC在其-Wunsequenced警告上也是如此。另外,当C++17刚刚实现时,一些较旧的编译器版本可能仍然存在这方面的错误。
发布于 2022-09-15 11:02:25
在……里面
foo(v).bar(std::move(v))没有任何保证(请参阅注释,预C++17),即foo(v)中的std::move(v)将在bar(std::move(v))中的std::move(v)之前进行评估。
整洁的文档提供了一个这方面的例子。
取消顺序的移动、使用和重新初始化 在许多情况下,C++不保证计算语句的子表达式的顺序。这意味着,在如下代码中,不能保证在移动之前还是之后使用: 空f(int i,std::向量v);std::向量v={ 1,2,3 };f(v1,std::move(v)); 在这种情况下,检查会注意到使用和移动是没有顺序的。 当在与移动或使用相同的语句中重新初始化时,检查还将考虑排序规则。只有保证在移动后和使用之前重新初始化变量时,才会考虑重新初始化。
https://stackoverflow.com/questions/73729536
复制相似问题