在std :: move之后使用对象不会导致编译错误

时间:2017-03-14 20:13:29

标签: c++ c++11 compilation move-semantics stdmove

在对象上调用std::move之后,如果在之后使用该对象,为什么该语言不会导致编译错误?

是因为编译器无法检测到这种情况吗?

5 个答案:

答案 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提供良好的基础,确实!)