Will C++ compiler optimize return-by-value code?

眉间皱痕 提交于 2019-12-01 19:44:58

问题


Lets assume i use Visual Studio or modern GCC with -O2. Will compiler create S inside func() and then copy it to a my_result, or will it create my_result with constructor (5, 6, 5 + 6) without creating temporary S?

NOTE: Function func() definition and its usage are in separate .obj files!

struct S
{
    S(int _x, int _y, int _z) : x(_x), y(_y), z(_z) { }
    int x, y, z;
};

S func(int a, int b)
{
    return S(a, b, a + b);
}


/// USAGE ///

S my_result = func( 5, 6 );

回答1:


Modern compilers will often optimize this kind of operation. See return value optimization




回答2:


It's an optimization which pretty much by definition means it's optional for the compiler and up to each aprticular compiler to decide what to do. How can you find out for sure? Check the disassembly of the generated code!

That said most compilers should do this optimization (return value optimization [RVO]) as it's relatively easy to do in this case (no multiple returns, it's an unnamed temporary so you don't have aliasing, etc).




回答3:


It seems to me that the provided test case is simple enough for RVO to apply.




回答4:


I would doubt the temporary is optimised out. You could test it by putting a print statement in the constructor and copy constructor and see what's printed under different compiler settings.




回答5:


You can test this yourself, because the optimization in question has observable differences!

Most forms of optimization in C++ follow the as-if rule, which makes them difficult to detect. However, in a few cases, eliding (skipping) copy and move constructor is allowed, even if the difference results in observable behavior changes.

In this case, add the following to S:

struct S {
  // ...
  S( S const& o ):x(o.x), y(o.y), z(o.z) {
    std::cout << "copy ctor!\n";
  }
  S& operator=( S const& o ) {
    x=o.x;
    y=o.y;
    z=o.z;
    std::cout << "copy assign!\n";
    return *this;
  }
  S( S && o ):x(std::move(o.x)), y(std::move(o.y)), z(std::move(o.z)) {
    std::cout << "move ctor!\n";
  }
  S& operator=( S const& o ) {
    std::tie( x,y,z ) = std::tie( std::move(o.x),std::move(o.y),std::move(o.z) );
    std::cout << "move assign!\n";
    return *this;
  }
}

and run your code. With zero optimization you'll get copies and/or moves.

With any non-trivial level of optimization, the prints will disappear, because RVO (and, in related cases, NRVO) will run, eliminating the copies. (If your compiler isn't C++11, remove the move constructors above -- the optimization in C++03 was still allowed)

In C++11 you can explicitly construct the return value instead of relying on NRVO/RVO via the return {stuff} syntax.

Note that RVO (return value optimization) and NRVO (named return value optimization) are relatively fragile, and if you are relying on them you both have to understand how they work, what makes them break, and any quirks your particular compiler has in its implementation (if any).



来源:https://stackoverflow.com/questions/18594241/will-c-compiler-optimize-return-by-value-code

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!