【问题标题】:When do you need to explicitly call std::move and when not in cpp?什么时候需要显式调用 std::move 什么时候不需要在 cpp 中?
【发布时间】:2021-09-09 07:32:31
【问题描述】:

我正在研究 Stroustrup 的“C++ v2 之旅”。这当然不是一本 C++ 初学者的书,但很有趣。

我用谷歌搜索过,但对此并不满意。

现在,我想我明白编译器何时可以使用移动构造函数,但显然我不明白。在这里,我展示了移动构造函数和我认为会使用它的函数。它没有。仅当我明确使用 std::move 时。为什么是这样?我的理解是本地 r 在返回时会被隐式“移动”。

template<typename T>
Vector<T>::Vector(Vector<T> && a) // move constructor
     :elem{a.elem},sz{a.sz}{
     a.elem=nullptr;
     a.sz=0;
}

template<typename T>
Vector<T> moveVectorAfterAdd(const Vector<T> &  v1, const Vector<T> & v2){
     Vector<T> r =   v1+v2;
     return std::move(r);
     //return r;
}

int main(void) {
     Vector<double> v1(1);
     Vector<double> v2=v1;
     Vector<double> v3=v2;

     Vector<double> v4=moveVectorAfterAdd(v1,v2);

     return 0;
}

(附带说明,如果我实际上不使用 std::move,尽管编译时没有优化,但 lldb 甚至不会让我在移动构造函数中设置断点。)

很高兴收到任何和所有澄清!

【问题讨论】:

  • 它不动是因为“没有工作比一些工作少”(从 CPPCon 谈话中无耻地窃取的引述):en.cppreference.com/w/cpp/language/copy_elision
  • 在非常不正式的措辞中,任何有名字的东西都是左值。 r 是一个有名字的变量。这是一个左值。 NRVO 涵盖了此用例,这是一种编译器优化,很可能会删除副本(如果您不使用 std::move)。
  • @RichieHH 是的。并且从 c++17 开始,您具有强制复制省略 (RVO),可以保证即使移动也可以省略。
  • @RichieHH 在 c++17 之前是编译器优化,在 c++17 之后是有保证的。例如,如果您同时删除了复制和移动构造函数,代码将无法编译,即使优化后的代码实际上并未使用它。
  • @Debashish:std::vector 的一些方法需要noexcept 在内部使用移动而不是复制。

标签: c++ c++11 move-constructor


【解决方案1】:

什么时候需要显式调用std::move,什么时候不在cpp中?

简而言之,技术上精确的话:当你有一个想要成为右值的左值时使用 std::move。更实际的是:当你想要一个副本而不是移动时,你会想要这样做。因此名称为 std::move。

在示例中,您返回一个自动变量。使用 std::move 无法避免复制,因为在返回自动变量的特殊情况下,即使从左值也会有移动。

这里我展示了移动构造函数和我认为会使用它的函数。没有。

仅仅因为抽象机器中有一个移动,并不一定意味着会调用移动构造函数。这是一件好事,因为什么都不做可能比调用移动构造函数更快。

这称为(命名)返回值优化。或更一般地,复制省略。使用 std::move 会抑制这种优化,因此在这种情况下不仅没有必要,而且还会适得其反。

【讨论】:

  • 我明白了很多,主要感谢 OP 中 @super 的耐心 cmets,但这也有帮助,所以我将其标记为答案。虽然我不太确定“适得其反”的地方适合。与我在 1999 年涉足的类相比,C 语言还有很长的路要走。我很高兴我不必使用多个版本的 C++ 标准来处理 C++。
  • 重新阅读,我确实看到在编译器可以使用 RVO 的情况下,使用 move 的地方效率低下。我将此作为单独的评论留下,以提醒我(也许还有其他人)在理解中出现轻微的打嗝。谢谢!
猜你喜欢
  • 1970-01-01
  • 2012-09-16
  • 1970-01-01
  • 1970-01-01
  • 2012-08-03
  • 2015-01-13
  • 2017-05-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多