Rvalue Reference Implications in C++11
There are several implications that one has to realize when it comes to using rvalue references in C++11 APIs. For starters, requiring an rvalue reference as a parameter to a function implies the following:
This is fairly large in terms of writing an API. In days of yore, before the existence of rvalues and move semantics, one might have used a pointer, or non-const reference to designate that an object would be mutated. They may have gone a step further and passed the object in by value to show that a deep copy would be made as the object passed in was no longer your concern. But none of these implied one very important feature that C++ technically lacks.
C99 added the
restrict keyword. When applied to a pointer, the programmer is
declaring to the compiler that for the lifetime of the pointer, only that
pointer or a value derived from that pointer (such as
pointer + some_offset)
will access the data to which it points. This limits pointer aliasing, and
helps the compiler to perform some cache optimizations.
C++ however does not have such a word. Yes, gcc and clang support the keyword
being applied to references, but this is non-standard (and I should note, also
sometimes breaks type traits and SFINAE if you expect a
T const& but pass a
T const& restrict) Now there are several proposals currently up for C++14 and
beyond where we will be able to apply
restrict as a modifier to types, and
I’m all for that as forcing constant lvalue references to not refer to the same
object is a good idea. But! Let us not foget the last implication of an
rvalue reference (a properly moved one at that). Specifically:
The rvalue reference is declaring to the compiler for the lifetime of that object, or a value derived from the object (such as
T const& = rvalue_reference) will access the data contained within the object.
In other words, an rvalue reference can declare to the compiler that the programmer intends for the object to only ever be accessed at on point.
Of course, this isn’t one hundred percent true, as an object that uses shallow copies internally would get around it. However, this also is also the same result as it would be in C99: Undefined Behavior. After all, declaring to the user that your API must fully and wholly own the object being passed in, and then magically mutating data contained within could be considered the same as casting away const on a reference, just so one may mutate it (which I should note is always 100% guaranteed to be undefined behavior, unless the original object it refers to was not declared const)
As far as I know, there are no compilers that will make assumptions or attempt to optimize based on this last implication. Whether they will or not also remains to be seen.