【问题标题】:Return value optimization of a member of a local stack variable局部堆栈变量成员的返回值优化
【发布时间】:2018-06-10 00:51:38
【问题描述】:

我有一段通用代码,在实例化时归结为:

struct A{...};

A f1(){
    A ret;
    std::pair<A&, int> p(ret, 1);
    p = g(); // g returns a pair<A, int>, but I am not interested in g
    return ret; // RVO :)
};

据我了解,这适用于 RVO。

问题是,这个其他代码会返回带有 RVO 的 A 类型的对象吗?

A f2(){
    std::pair<A, int> p;
    p = g();
    return p.first; // RVO ?
};

我了解,由于返回对象被遮挡,它不会执行 RVO,或者编译器可能无法选择“优化”。 但我看不出它不可能的根本原因,换句话说,我认为为了保持一致性,它应该做 RVO(我想要)。

之所以问,是因为我认为f2f1 更优雅的代码。

最后一个版本应该做 RVO 吗?如果是,它是否依赖于编译器?


我对 gcc 8.1 的粗略测试表明 RVO 在下面的 f2f3 中不起作用:

struct A{
    double something;
    A() = default;
    A(A const& other) : something(other.something){std::cerr << "cc" << '\n';}
    A(A&& other) : something(other.something){std::cerr << "mc" << '\n';}
};

A f1(){
    A ret;
    std::pair<A&, int> p(ret, 1);
    p.first.something = 5.;
    return ret; // RVO :)
};

A f2(){
    std::pair<A, int> p;//(ret, 1);
    p.first.something = 5.;
    return p.first; // no RVO :(
};

A f3(){
    std::pair<A, int> p;//(ret, 1);
    p.first.something = 5.;
    return std::move(p).first; // no RVO :(
};


int main(){
    A a1 = f1(); // prints nothing, RVO
    A a2 = f2(); // prints "cc"; no RVO! Why?
    A a3 = f3(); // prints "mc" (no much gain in this case); still no RVO!
}

【问题讨论】:

  • 这种情况通常称为NRVO
  • return std::move(p.first); 是你将得到的最好的

标签: c++ reference member-variables return-value-optimization


【解决方案1】:

要使 RVO 工作,返回值需要在调用者期望找到它的存储中实例化。也许这是一个名称由调用约定指定的寄存器,或者它在堆栈上。

std::pair&lt;A, int&gt; 本质上是:

struct foo {
    A first;
    int second;
};

现在,如果需要将返回值存储在sizeof(A) 的特定位置,但该对的大小较大,则该对不可能存储在那里。仍然可以使 RVO 工作的唯一方法是,如果被调用者知道在函数执行时允许破坏返回值后面的 sizeof(int) 字节。但在这种情况下,该语言可能不需要 RVO,因为它可能无法在每个调用约定中实现。

【讨论】:

  • 标准是否涵盖这些规则?这很完美,但我只是好奇......
  • C++ 标准通常不涵盖实现细节,但在编写时知道它是可实现的(通常以现有实现作为证明)。您希望的 RVO 可能无法在所有平台上实现。
  • 可以理解。我想我可以添加返回元素是类的第一个成员的案例细化。所以它可以在堆栈的开头。
猜你喜欢
  • 1970-01-01
  • 2015-05-08
  • 1970-01-01
  • 2013-09-27
  • 2017-04-17
  • 1970-01-01
  • 1970-01-01
  • 2020-06-22
  • 2022-12-20
相关资源
最近更新 更多