6

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?

R.M.
  • 3,461
  • 1
  • 21
  • 41
  • To the person who voted close based on "unclear what you're asking", I'd be happy to clarify if you gave a general sense as to what you're unclear about. -- The core of the issue is that the code in the third block makes a copy even if apply_alteration is false. I want to do what the third block does, but without that copy. – R.M. Feb 08 '19 at 23:03

2 Answers2

4

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) {
    // ...
}
Iłya Bursov
  • 23,342
  • 4
  • 33
  • 57
  • I agree with this: the operation on the object (`func_internal` here) should be its own function, and the logic to decide which object to operate on is distinct from that – M.M Feb 08 '19 at 23:16
0

Maybe adding a 2nd parameter to func()?

void func( MyObject const& original, bool modify = false ) {
    if ( modify )  MyObject const & altered( alter_obj( original ) );
    else MyObject const & not_altered( original ); 
}

Might achieve what you are looking for...

Francis Cugler
  • 7,788
  • 2
  • 28
  • 59
  • Coming up with the `modify` bool is not the issue here. The difficulty is putting the appropriate object into the same variable. At any rate, your if/else approach does not really work, as variables declared within an if and/or else clause are not visible to any code outside of them. (Which means you'd have to duplicate the following code where you actually use the variable within the if and else blocks.) – R.M. Feb 09 '19 at 03:28
  • @R.M. Oh okay I understand what you are saying... But I was thinking that the bool parameter wasn't being declared within the if statement as it was a passed in parameter and depending on that parameter it would call the appropriate function... – Francis Cugler Feb 09 '19 at 05:21