在对象上调用std::move
之后,如果在之后使用该对象,为什么该语言不会导致编译错误?
是因为编译器无法检测到这种情况吗?
答案 0 :(得分:9)
C ++语言设计的一般原则是"信任程序员"。我可以想到的一些问题,在它成为std::move
的参数之后拒绝使用该对象。
std::move
之后是否等同于解决暂停问题。 (换句话说,它无法完成。)你必须提出一些规则来描述你的意思"""以一种可以静态决定的方式。std::move
参数的对象是完全安全的。 (一个特定的类可能会导致断言,但这将是一个非常奇怪的设计。)答案 1 :(得分:6)
请记住,std::move
只不过是对右值引用的强制转换。它本身实际上并没有移动任何东西。此外,该语言仅声明从对象移动的处于有效/可破坏状态,但除此之外没有说明其内容 - 它可能仍然完整,它可能不是或(与std::unique_ptr
一样,它可以定义为具有特定内容(nullptr
)) - 这一切都取决于移动构造函数/移动赋值运算符的实现。
因此,访问移动的对象是否安全/有效完全取决于特定对象。移动后阅读std::unique_ptr
,看看它是nullptr
是完全正确的 - 例如 - 对于其他类型;没那么多。
答案 2 :(得分:4)
这就是所谓的“实施质量”问题:对于一个好的编译器或工具链来说,为一个有潜在危险的移动后使用情况发出警告比使用正式禁止它的语言标准更有意义精确定义的一组情境。毕竟,移动后的一些用法是合法的(例如std::unique_ptr
的情况,在移动后保证为空)而其他未定义的情况不容易被检测到 - 一般来说,检测移动对象后是否使用对象等同于暂停问题。
您可以使用clang-tidy来检测移动后的使用情况:https://clang.llvm.org/extra/clang-tidy/checks/misc-use-after-move.html
答案 3 :(得分:4)
这是因为我们经常想要使用move-from对象。考虑std::swap
的默认实现:
template<typename T>
void swap(T& t1, T& t2)
{
T temp = std::move(t1);
t1 = std::move(t2); // using moved-from t1
t2 = std::move(temp); // using moved-from t2
}
每次使用std::swap
时,您都不希望编译器发出警告。
答案 4 :(得分:0)
对象的移动后状态的性质由实现者定义;在某些情况下,移动对象可能会使其处于完全可用的状态,而在其他情况下,对象可能会变得无用(或者更糟糕的是,某种程度上使用起来很危险)。
虽然我有点同意 - 最好有选择产生警告,至少,如果一个对象在移动后以潜在的危险方式使用,我不知道GCC或Clang的选项提请注意这种类型的代码气味。
(事实上,对于无畏者来说,这可能会为a Clang plugin提供良好的基础,确实!)