【问题标题】:RVO, move semantics and the struggle towards optimal codeRVO,移动语义和优化代码的斗争
【发布时间】:2014-01-05 03:37:30
【问题描述】:

如果我理解正确,移动语义允许从临时的、未命名的对象中移动和重用资源。 RVO,尽管前面的移动语义走得更远,“窃取”了整个对象,以避免额外的构造函数调用和赋值/复制函数。

这对我来说似乎有点反直觉,如果被调用的构造函数直接使用最终左值目标的地址来直接将数据放置在用户需要的位置,那不是更快、更简单和用户明显吗?

我的意思是,“在这个位置创建这个对象”似乎比“在某个地方创建这个对象,然后将它复制到正确的位置”更直观。

【问题讨论】:

  • 好问题。我没有时间想一个完整的答案,但我相信调用链会让这成为一场噩梦(例如A a = f(g(), h(i(), j()), k(l()));)。现在用户必须告诉fghijkl 中的每一个它应该在哪里创建返回值。
  • @Angew - 在这种情况下,只有f()会直接返回a的地址,其余的会返回它们用来调用f()的临时对象的地址。毕竟,唯一的分配是从f()的返回到a
  • 是的,但按照我的理解,这些临时对象可以直接在参数的位置(RVO)或函数的返回值位置中构造。
  • 我认为这(接近)回答了同一个问题“如果我们已经拥有 RVO,移动语义会提供什么优化?” - stackoverflow.com/questions/5031778/…
  • @user2341104 如果您对提供地址的编译器感到满意,那么我一定误解了这个问题。 RVO 正是“在这个位置创建这个对象”。那么你到底在问什么?

标签: c++ optimization move-semantics return-value-optimization emplace


【解决方案1】:

是的,它“有点反直觉”。启用复制省略后,构造函数的所有副作用也会被省略。

#include <iostream>

struct X {
    X() { std::cout << "Construct" << std::endl; }
    X(X&&) { std::cout << "Move" << std::endl; }
    ~X() { std::cout << "Destruct" << std::endl; };
};

X f() { return X(); }

int main()
{
    X x(f());
    return 0;
}

复制省略:g++ -std=c++11 src-test/main.cc

Construct
Destruct

无复制省略:g++ -std=c++11 -fno-elide-constructors src-test/main.cc

Construct
Move
Destruct
Move
Destruct
Destruct

编译器知道程序/库所针对的硬件,能够应用(可选)复制省略。 C++ 语言本身不知道硬件特定的返回机制。因此,在这种情况下不可能在某个地址构造。

【讨论】:

    猜你喜欢
    • 2013-12-19
    • 2011-06-29
    • 1970-01-01
    • 2018-08-04
    • 2014-09-13
    • 2015-07-07
    • 1970-01-01
    相关资源
    最近更新 更多