Thursday, October 9, 2008

c++: RVO and NRVO

RVO is stands for "return value optimization" and NRVO for "named return value optimization".
What does all this staff mean?

Typically, when a function returns an instance of an object, a temporary object is created and copied to the target object via the copy constructor.

RVO is a simple way of optimization when compiler doesn't create temporary when you return anonymous instance of class/structure/etc. from the function.

class C
{
    public:
        C() 
        {
            std::cout << "Constructor of C." << std::endl;
        }
        C(const C &)
        {
            std::cout << "Copy-constructor of C." << std::endl;
        }
};

C func()
{
    return C();
}

int main(int argc, char **argv)
{
    C c = func();

    return 0;
}
The output should be
Constructor of C.
Here compiler do not make a copy of C instance on return. This is a great optimization since construction of the object takes time. The implementation depends on compiler but in general compiler extends function with one parameter - reference/pointer to the object where programmer wants to store the return value and actually stores return value exact into this parameter.
It may look like
C func(C &__hidden__)
{
    __hidden__ = C();
    return;
}
NRVO is more complex. Say you have
class C
{
    public:
        C()
        {
            std::cout << "Constructor of C." << std::endl;
        }
        C(const C &c) 
        {
            std::cout << "Copy-constructor of C." << std::endl;
        }
};

C func()
{
    C c;
    return c;
}

int main(int argc, char **argv)
{
    C c = func();

    return 0;
}
Here compiler should deal with named object c. With NRVO temporary object on return shouldn't be created. The pseudocode of
C func()
{
    C c;
    c.method();
    c.member = 10;
    return c;
}
might look like
C func(C &__hidden__)
{
    __hidden__ = C();
    __hidden__.method();
    __hidden__.member = 10;
    return;
}
In both cases temporary object is not created for copying(copy-constructor is not invoked) from the function to the outside object.

When this may not work?
Situation I known when these optimizations won't work when function have different return paths with different named objects.

No comments: