Index: base/move.h |
diff --git a/base/move.h b/base/move.h |
index daead8d2dddd9b236d83c314dbb41d8054d282d3..7fcb8dd94c452ce3670447b41234f71f849617cc 100644 |
--- a/base/move.h |
+++ b/base/move.h |
@@ -69,7 +69,7 @@ |
// alternate conversion sequence and a constructor. We add |
// |
// * a private struct named "RValue" |
-// * a user-defined conversion "operator RValue&()" |
+// * a user-defined conversion "operator RValue()" |
// * a "move constructor" and "move operator=" that take the RValue& as |
// their sole parameter. |
// |
@@ -92,8 +92,8 @@ |
// |
// public: |
// ... API ... |
-// Foo(RValue& other); // Move constructor. |
-// Foo& operator=(RValue& rhs); // Move operator= |
+// Foo(RValue other); // Move constructor. |
+// Foo& operator=(RValue rhs); // Move operator= |
// }; |
// |
// Foo MakeFoo(); // Function that returns a Foo. |
@@ -111,31 +111,29 @@ |
// |
// IMPLEMENTATION SUBTLETIES WITH RValue |
// |
-// The RValue struct has subtle properties: |
+// The RValue struct is just a container for a pointer back to the original |
+// object. It should only ever be created as a temporary, and no external |
+// class should ever declare it or use it in a parameter. |
// |
-// 1) All its methods are declared, but intentionally not defined. |
-// 2) It is *never* instantiated. |
-// 3) It is a child of the move-only type. |
+// It is tempting to want to use the RValue type in function parameters, but |
+// excluding the limited usage here for the move constructor and move |
+// operator=, doing so would mean that the function could take both r-values |
+// and l-values equially which is unexpected. See COMPARED To Boost.Move for |
+// more details. |
// |
-// (1) is a guard against accidental violation of (2). If an instance of |
-// RValue were ever created, either as a temporary, or as a copy to some |
-// function parameter or field of a class, the binary will not link. |
+// An alternate, and incorrect, implementation of the RValue class used by |
+// Boost.Move makes RValue a fieldless child of the move-only type. RValue& |
+// is then used in place of RValue in the various operators. The RValue& is |
+// "created" by doing *reinterpret_cast<RValue*>(this). This has the appeal |
+// of never creating a temproary RValue struct even with optimizations |
+// disabled. Also, by virtue of inheritance you can treat the RValue |
+// reference as if it were the move-only type itself. Unfortuantely, |
+// using the result of this reinterpret_cast<> is actually undefined behavior |
+// due to C++98 5.2.10.7. In certain compilers (eg., NaCl) the optimizer |
+// will generate non-working code. |
// |
-// This ensures that RValue can only exist as a temporary which is important |
-// to avoid accidental dangling references. |
-// |
-// (3) allows us to get around instantiations because our user-defined |
-// conversion can return a downcast of this pointer. |
-// |
-// operator RValue&() { return *reinterpret_cast<RValue*>(this); } |
-// |
-// Because RValue does not extend the object size or add any virtual methods, |
-// this type-pun is safe. |
-// |
-// An alternative implementation would be to make RValue into a concrete |
-// struct that holds a reference to the type. But in the non-optimized build, |
-// this causes unnecessary temporaries to be made bloating the object files. |
-// Also, it would then be possible to accidentally persist an RValue instance. |
+// In optimized builds, both implementations generate the same assembly so we |
+// choose the one that adheres to the standard. ☃ |
// |
// |
// COMPARED TO C++11 |
@@ -154,8 +152,8 @@ |
// |
// COMPARED TO Boost.Move |
// |
-// Our implementation is based on Boost.Move, but we keep the RValue struct |
-// private to the move-only type. |
+// Our implementation similar to Boost.Move, but we keep the RValue struct |
+// private to the move-only type, and we don't use the reinterpret_cast<> hack. |
// |
// In Boost.Move, RValue is the boost::rv<> template. This type can be used |
// when writing APIs like: |
@@ -195,17 +193,15 @@ |
// |
#define MOVE_ONLY_TYPE_FOR_CPP_03(type, rvalue_type) \ |
private: \ |
- struct rvalue_type : public type { \ |
- rvalue_type(); \ |
- ~rvalue_type(); \ |
- rvalue_type(const rvalue_type&); \ |
- void operator=(const rvalue_type&); \ |
+ struct rvalue_type { \ |
+ rvalue_type(type* object) : object(object) {} \ |
+ type* object; \ |
}; \ |
type(type&); \ |
void operator=(type&); \ |
public: \ |
- operator rvalue_type&() { return *reinterpret_cast<rvalue_type*>(this); } \ |
- type Pass() { return type(*reinterpret_cast<rvalue_type*>(this)); } \ |
+ operator rvalue_type() { return rvalue_type(this); } \ |
+ type Pass() { return type(rvalue_type(this)); } \ |
private: |
#endif // BASE_MOVE_H_ |