
On Wed, Apr 24, 2013 at 5:31 PM, Andrew Ho
I was assuming T was a given type:
struct T : addable<T> { // ... }
But I did some testing, and looks like the above code which normally should fail if operator+ returned a lvalue reference actually works with rvalues:
struct T : boost::addable<T> { T(void) { std::cout << "T(): " << this << std::endl; }
T(const T &val) { std::cout << "T(const T&): " << this << std::endl; }
T(T &&val) { std::cout << "T(T&&): " << this << std::endl; }
~T(void) { std::cout << "~T(): " << this << std::endl; }
T& operator +=(const T& op) { std::cout << this << " += " << &op << std::endl; return *this; } T& operator =(const T& op) { std::cout << this << " = const & " << &op << std::endl; return *this; }
T& operator =(T&& op) { std::cout << this << " = && " << &op << std::endl; return *this; } };
Output using VS2012 (displayed output in debug mode, but similar results occur in release mode):
T &result = t1 + t2 + t3;
T(): 0040FEDB T(): 0040FECF T(): 0040FEC3 T(const T&): 0040FCD7 0040FCD7 += 0040FECF T(T&&): 0040FEAB ~T(): 0040FCD7 0040FEAB += 0040FEC3
&result = 0040FEAB
T result = t1 + t2 + t3;
T(): 0035F9FF T(): 0035F9F3 T(): 0035F9E7 T(const T&): 0035F7FB 0035F7FB += 0035F9F3 T(T&&): 0035F90F ~T(): 0035F7FB 0035F90F += 0035F9E7 T(T&&): 0035F9DB ~T(): 0035F90F
&result = 0035F9DB
Is this just MS trying to be "clever", or are these results standard-compliant (and equally important, viable on all other rvalue-ref aware compilers)? If this is indeed expected behavior, then there shouldn't be any fuss over unsafe behavior at all, and the 4-overload version can be used without any problems (assuming we didn't miss any corner cases).
1) Please don't top-post. 2) I think my responses below still apply. 3) I suspect if you did T& x = f() + g(), where f() and g() are rvalues, you'd be in trouble. On Wed, Apr 24, 2013 at 3:41 PM, Jeffrey Lee Hellrung, Jr. <
jeffrey.hellrung@gmail.com> wrote:
On Wed, Apr 24, 2013 at 1:36 PM, Andrew Ho
wrote: Remind me how the 4-overload-version is unsafe, again?
There's the potential for a user to assign a reference variable to an invalid temporary:
T &var = a + b + c;
Does operator+ return by value or by reference? If it returns by value, how is the above possible? Is T a typedef or template parameter for a const-qualified type in your example above?
I am of the opinion this is a usage error (as is Daniel), but
none-the-less, was previously valid because the operators returned by value.
Okay, now I'm really confused. I would think return-by-reference would allow the above, but return-by-value would not.
And how is this related to whether operator+'s parameters are by-value (1 overload) or by-reference (4 overloads)? I mean, other than the former precluding return-by-reference, of course.
Just as large a problem is that if this error does occur in real
code (old or new), it can be difficult to identify.
A macro which globally switches the effect of all uses of Boost.Operators? Let's avoid that.
We will need at least the compiler feature check switch since rvalue references will cause compilers which don't support the feature fail.
Yeah, that's fine; you're switching on compiler features, and you're switching to an objectively better implementation.
Having a macro that switches *all* uses of Boost.Operators to either "safe" or "fast" (whatever those mean) implies that you can't mix safe uses with fast uses.
After
a little digging, the commutative operators will always need special handling since they directly use rvalue refs.
On Wed, Apr 24, 2013 at 11:04 AM, Jeffrey Lee Hellrung, Jr. < jeffrey.hellrung@gmail.com> wrote:
On Tue, Apr 23, 2013 at 11:06 PM, Andrew Ho
wrote:
Here's a thought about the direct use of r-value references vs. pass by value argument:
We are planning on providing a version which is supposed to support compilers without move semantics. However, these implementations are close to, perhaps even exactly identical to the code that would take advantage of move semantics via pass by value.
Say we allowed a user-accessible define which would allow the programmer to decide?
A macro which globally switches the effect of all uses of Boost.Operators? Let's avoid that.
something like:
// BOOST_HAS_RVALUE_REFS is a feature availability check // BOOST_UNSAFE_MOVE is user-definable override to use faster,
version #if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_UNSAFE_MOVE) // use 4 overload version #else // use pass-by-value version #endif
If the user is more concerned with safety over micro-optimizations,
unsafe the
default behavior would resort to pass by value (good for backwards compatibility).
Remind me how the 4-overload-version is unsafe, again?
However, the user would have the option available to easily use the faster
version if they deem it necessary.
- Jeff
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- Andrew Ho
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- Andrew Ho
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost