Why RVO and NRVO are not made obligatory by the standard?

1.1k views Asked by At

Why RVO and NRVO optimizations are not made obligatory (when they are applicable) by the standard? e.g. there is a very common case when a function produces some object and returns it as the result. The copy/move constructors are usually elided because of RVO/NRVO, but they still need to be defined, which is somewhat confusing. If RVO/NRVO was in the standard, the copy/move constructors would be no longer required in this case.

1

There are 1 answers

4
Nicol Bolas On

Copy elision is not required by the standard because that would require all implementations to implement it in all cases.

Just look at the case of return-value-optimization vs named-return-value-optimization. Simply turning this:

std::string Func()
{
  return std::string("foo");
}

Into this functionally identical code:

std::string Func()
{
  std::string named("foo");
  return named;
}

The latter requires a lot more out of the compiler than the former. Different compilers support NRVO in different circumstances. Sure, most of them support it in this trivial case, but there are a lot of different cases out there. And there are some cases where compilers just say "screw it" and doesn't do the optimization altogether.

Your way would require one of the following:

  1. To enforce copy elision in all applicable cases, no matter how difficult to implement for compilers. So now every compiler writer has to deal with the cases like this:

    std::string Func(bool b)
    {
      if(b)
      {
        std::string named("foo");
        return named;
      }
      else
      {
        std::string named("bar");
        return named;
      }
    }
    

    Many compilers don't handle NRVO in those cases. And that's a simple case; they can get much more complex than that.

  2. Go through every compiler and find a common subset of cases where copy elision is always used, then specify them in the standard as requirements. That's utterly ludicrous; you'd be standardizing based on implementation details. That's never a good thing.

Note that C++17 may be getting a guarantee of copy elision in a specific case. Namely, elision is required for a copy/move any time a temporary is used to initialize an object of the same type. This makes it possible to return an immobile object from a function.