Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to efficiently bind either an lvalue or rvalue to the same reference?

Say you have a C++ function which uses an altered version of a (const) parameter.

MyObject alter_obj( MyObject const & obj ); // Creates new, altered object

void func( MyObject const & original ) {
    MyObject const & altered( alter_obj( original ) );
    // ...
}

This works properly, due to the lifetime extension of the temporary because of the "most important const". It's also rather efficient if alter_obj() meets the requirements for return value optimization, as RVO means the altered object returned by value is not unnecessarily copied.

It would also be efficient if you didn't make the alteration at all:

void func( MyObject const & original ) {
    MyObject const & not_altered( original );
    // ...
}

Additional references to a given object are basically free, without any performance overhead of making a copy.

But say requirements change a bit, and you want to choose whether or not to make the alteration depending on runtime conditions. Naively, I would have expected that using the ternary operator to combine the two previous approaches would be efficient, binding the original object directly when possible, or binding the temporary if not.

MyObject alter_obj( MyObject const & obj ); // Creates new, altered object

void func( MyObject const & original ) {
    // ...
    MyObject const & possibly_altered( 
        apply_alteration ? 
        alter_obj( original ) : 
        original 
    );
    // ...
}

However, it appears that this approach is not as efficient as I would have hoped. The ternary operator apparently requires the last two parameters match on lvalue/rvalue status, not just on nominal type. This means that when the false (no alteration) branch is taken, an rvalue temporary is made by invoking the copy constructor of MyObject on original. If MyObject is non-trivial to copy, there's a potential performance penalty due to making this "spurious" copy.

Is there a good way around this? Is it possible to efficiently bind a local reference to either another existing reference or a temporary (choice based on runtime values) without making additional copies?

like image 786
R.M. Avatar asked Feb 08 '19 22:02

R.M.


1 Answers

I'd create separate function, which accept reference and call it, like this:

void func( MyObject const & original ) {
    if (apply_alteration)
        func_internal(alter_obj(original));
    else
        func_internal(original);
}

void func_internal( MyObject const & possibly_altered) {
    // ...
}
like image 147
Iłya Bursov Avatar answered Oct 13 '22 01:10

Iłya Bursov