I've seen it recommended (see here, for example) that if you want to create a copy of a parameter to a function, then you should pass it by value so that the copy is done automatically in the initialization list.
I.e., instead of writing
void some_function_ref(Some_class const& input)
{
Some_class copy_of_input(input);
// Do something with copy_of_input
}
, we should write
void some_function_val(Some_class input)
{
// Do something with input
}
. In C++11, there's an elegant reason for this: the second case will choose between calling the copy constructor or the move constructor depending on whether it is passed an lvalue or an rvalue, whereas the first case always calls the copy constructor.
For example, if we call
some_function_ref(function_that_returns_some_class())
, then the program will create a temporary to store the return value of function_that_returns_some_class
, and then make a copy of this temporary inside the function. Whereas if we call
some_function_val(function_that_returns_some_class())
, then the program will create a temporary as before, but will now move the temporary into the function and use that value internally. We have avoided the needless copy.
However, some_function_ref
has advantages of its own: if we want to make our code easy to debug, then it might be helpful to see the value of input
that was passed into the function. If some_function
has been passed an lvalue, then we can see this value by inspecting the value of the variable in the enclosing scope. However, if it has been passed an rvalue, we might have no way of seeing what it is.
Of course, there is a reason for this: if the function has been called with an rvalue, then some_function_val
will use the move constructor on the temporary, which means that it the old value no longer exists! From an optimization point of view, this is great, since we've avoided an extra copy. From a debugging point of view, it's not so good.
What would be really nice is if we could see the original value of input
in an unoptimized debug build of the code, but have the value moved in an optimized release build. For that reason, I would be tempted to use the first version (some_function_ref
), under the assumption that the compiler will optimize away the copy and call the move constructor instead if I've turned optimization on, effectively converting some_function_ref
into some_function_val
.
Is this a reasonable assumption to make? Is the compiler (think gcc, clang etc.) smart enough to realize that input
is only used to make a copy and optimize some_function_ref
to do the same thing as some_function_val
?
Aucun commentaire:
Enregistrer un commentaire