简体   繁体   English

本地堆栈变量成员的返回值优化

[英]Return value optimization of a member of a local stack variable

I have a piece of generic code that, when instantiated, boils down to: 我有一段通用代码,在实例化时,归结为:

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 :)
};

As far as I understand, this will work with RVO. 据我了解,这将适用于RVO。

The question is, would this other code return the object of type A with RVO? 问题是,这个其他代码是否会返回带有RVO的A类对象?

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

I understand that since the return object is obscured, it will not do RVO or that the compiler may not be able to pick the "optimization". 我理解,由于返回对象被遮挡,它不会做RVO或者编译器可能无法选择“优化”。 But I don't see a fundamental reason why it wouldn't be possible, in other words, I think for consistency, it should do RVO (which I want). 但我没有看到为什么它不可能的根本原因,换句话说,我认为一致性,它应该做RVO(我想要)。

The reason I ask, it because I think f2 is more elegant code than f1 . 我问的原因是因为我觉得f2f1更优雅。

Should this last version do RVO? 这最后一个版本应该做RVO吗? If so, is it compiler dependent? 如果是这样,它是编译器依赖的吗?


My crude test with gcc 8.1 gives that RVO doesn't work in f2 and f3 below: 我用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!
}

For RVO to work, the return value needs to be instantiated in the storage where the caller expects to find it. 要使RVO工作,需要在调用者期望找到它的存储中实例化返回值。 Perhaps this is a register whose name is specified by the calling convention, or perhaps it is on the stack. 也许这是一个寄存器,其名称由调用约定指定,或者它可能在堆栈中。

std::pair<A, int> is essentially: std::pair<A, int>本质上是:

struct foo {
    A first;
    int second;
};

Now, if the return value needs to be stored at a specific place with sizeof(A) , but the pair has a larger size, the pair cannot possibly be stored there. 现在,如果返回值需要存储在sizeof(A)的特定位置,但该对具有更大的大小,则该对不可能存储在那里。 The only way RVO could still be made to work is if the callee knew that the sizeof(int) bytes following the return value were allowed to be clobbered while the function was executing. RVO仍然可以工作的唯一方法是,如果被调用者知道在执行函数时允许返回值后面的sizeof(int)字节被破坏。 But the language probably shouldn't require RVO in such a case, because it might not be implementable in every calling convention. 但在这种情况下,语言可能不应该要求RVO,因为它可能无法在每个调用约定中实现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM