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
- The object being passed in may be mutated
- The object being passed in may exist until program exit
- You (the caller) no longer own the object being passed in
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 the 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 breaks type traits and SFINAE if you expect a
T const& but pass in 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 forget 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 that only that object, or a value derived from the object (such as
T const& = rvalue_referencewill 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 one 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 results in the same result as it would 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 that one may mutate it (which, I should note, is always 100% guaranteed to be undefined behavior)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.