Boost logo

Boost :

Subject: Re: [boost] [move] auto-generated operator=
From: Jeffrey Hellrung (jhellrung_at_[hidden])
Date: 2009-11-16 14:44:49


David Abrahams wrote:
> On Nov 16, 2009, at 7:46 AM, David Abrahams wrote:
>
>> On Sep 8, 2009, at 5:52 AM, Ion Gaztañaga wrote:
>>
>>> We need a third alternative: a new overload set that maintains "const T &" and properly catches non-const rvalues.
>> I think we have it:
>>
>> define one copy assignment operator in terms of swap. Copy elision makes it nearly as fast as a move, and we don't get an operator=(T&) infection in derived classes.
>>
>> I have no problem with requiring move-enablers to supply a swap.
>
> In fact, I don't even think we need to do that. This seems to work pretty well:
>
> #define BOOST_COPYABLE_AND_MOVABLE(TYPE)\
> public:\
> TYPE& operator=(TYPE t)\
> { return this->operator=(static_cast< ::boost::rv<TYPE>&>(t)); } \
> public:\
> operator ::boost::rv<TYPE>&() \
> { return *reinterpret_cast< ::boost::rv<TYPE>* >(this); }\
> operator const ::boost::rv<TYPE>&() const \
> { return *reinterpret_cast<const ::boost::rv<TYPE>* >(this); }\
> private:\
> //
>
> --
> David Abrahams
> BoostPro Computing
> http://boostpro.com
>

I think this was similar to what Ion had before, no? Only the user had
to explicitly provide the copy assignment (which accepted a by-value
parameter).

The downside is the double copy of non-movable objects during copy
assignment when no copy elision can kick in:

copyable_and_movable x(...);
copyable_and_movable y(...);
x = y; // non-movable stuff in y is copied twice, right?

In fact, copyable_and_movable may not even have anything movable in it
(if it's templated, e.g., std::pair), so operator=(T) does twice as much
work as operator=(const T&) !

The "current" solution (that which is in the sandbox, using
BOOST_COPY_ASSIGN_REF) avoids this double copying at the expense
auto-generating an operator= that accepts non-const references.

Also, as Ion mentioned, currently acquired resources can't be reused if
your copy assignment signature accepts by value.

That said, I think I'd prefer a by-value operator=, as it seems
reasonably close to optimal and gives better semantic behavior regarding
auto-generated operator=.

Is there some way to generate a (close to) optimal operator= overload
for std::pair? I.e., the BOOST_COPYABLE_AND_MOVABLE macro provides one
of operator=(const pair&) or operator=(pair) depending on some compiler
time boolean value? I'm thinking:

template< class T0, class T1 >
pair
{

private:
     static const bool should_move = T0::should_move || T1::should_move;
// obviously not exactly this but the intent should be clear...
     BOOST_COPYABLE_AND_MOVABLE( pair ) // refers to should_move to
decide whether to generate operator=(const pair&) or operator=(pair)

public:
     T0 first;
     T1 second;
};

Something like:

template< class T >
typename boost::enable_if_c< boost::is_same< T, pair >::value &&
should_move, pair& >::type
operator=(T x);
template< class T >
typename boost::enable_if_c< boost::is_same< T, pair >::value &&
!should_move, pair& >::type
operator=(const T& x);

Is this worth pursuing?

Also, the conversion operator to const rv<T>& is a must, as it allows
all functions sans T::operator= to be overloaded on const rv<T>&, T&,
and rv<T>& to truly capture rvalues by reference.

- Jeff


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk