Will "copy elision" and "named return value optimization (NRVO)" work in a recursive function?

Will "copy elision" and "named return value optimization (NRVO)" work in a recursive function?

Problem Description:

In C++, compilers are specifically allowed to perform "copy elision," and more specifically "named return value optimization," (NRVO) such that a function-local variable isn’t even move()‘d to a variable in the caller’s stack frame, but is in fact itself in the caller’s stack frame.

Can this be assumed to work with recursive functions? Or should I have the caller manually pass in the storage?

vector<MyClass*> MyClass::GetHeirarchy() {
    vector<MyClass*> apclass;

    if ( pclassParent )
        apclass = pclassParent->GetHeirarchy();

    apclass.push_back( this );
    return apclass;    
}

Here’s the same function written without assuming NRVO. Oddly, it seems shorter and simpler.

void MyClass::GetHeirarchy( vector<MyClass*>* papclass ) {

    if ( pclassParent )
        pclassParent->GetHeirarchy( papclass );

    apclass->push_back( this );
}

Solution – 1

There is no elision here:

apclass = pclassParent->GetHeirarchy();

This is assignment. It is always assignment. Elision is about the initialization of an object. apclass is already initialized at this point, so this just assigns to an existing object.

If you want elision to be possible within a recursive call, then you need to either return GetHeirarchy directly or use its return value to initialize a local that you then return with modifications.

But in general, the kind of algorithm you’re implementing (where you’re conceptually creating a single object through recursive manipulation of said object) is not something where elision will be generally helpful. The final object can be elided, but the various steps that manipulate the object should be done as clear object manipulation:

void MyClass::GetHeirarchyRec( vector<MyClass*>& apclass ) {

    if ( pclassParent )
        pclassParent->GetHeirarchyRec( apclass );

    apclass.push_back( this );
}

void MyClass::GetHeirarchy()
{
    vector<MyClass*> ret;
    GetHierarchyRec(ret);
    return ret;
}

This way, the user interface of just receiving an array is preserved.

Rate this post
We use cookies in order to give you the best possible experience on our website. By continuing to use this site, you agree to our use of cookies.
Accept
Reject