Boost logo

Boost :

Subject: Re: [boost] [variant] Please vote for behavior (Was: Basic rvalue and C++11 features seupport)
From: Edward Diener (eldiener_at_[hidden])
Date: 2013-01-21 23:02:32


On 1/21/2013 8:39 AM, Antony Polukhin wrote:
> Current implementation of recursive_wrapper move constructor is not optimal:
>
> recursive_wrapper<T>::recursive_wrapper(recursive_wrapper&& operand)
> : p_(new T(std::move(operand.get()) ))
> { }
>
> During descussion were made following proposals:
>
> I: Leave it as is
> - bad performance
> - can not provide noexcept guarantee
>
> II: Set operand.p_ to NULL, add BOOST_ASSERT in get operations
> + good performance
> + provides noexcept guarantee for move constructor
> + optimization will be used even if varinat has no type with trivial
> default constructor
> + easy to implement
> - triggers an assert when user tries to reuse moved object
> - adds an empty state to the recursive_wrapper
>
> III: Make recursive_wrapper and variant cooperate, enable move for
> varinat in the presence of recursive_wrappers only when there is at
> least one type that is nothrow-default-constructible, regardless of
> whether it's current. It is easyer to understand by example:
> typedef variant<int, recursive_wrapper<foo>> V;
> V v1( std::move(v2) );
> This move-constructs v1 from v2 and leaves int() into v2.
> + good performance
> + provides noexcept guarantee for rcursive_wrapper
> + does not adds an empty state
> - optimization won't trigger if varinat has no type with trivial
> default constructor
> - hard to implement
> - user may be obscured by the fact, that v2 from the example now contains int
>
> IV: After move away, delay construction of type held by
> recursive_wrapper till it will be be required.
> +/- good performance? but more checks
> + provides noexcept guarantee for rcursive_wrapper
> + does not adds an explicit empty state
> + optimization will be used even if varinat has no type with trivial
> default constructor
> +/- not hard to implement
> --- additional requirement for type T of recursive_wrapper: it must
> be default constructible
> - less obvious behavior for user (for example get() function would
> construct values, allocate memory and can possibly throw)

The main issue seems to be simply this: are guarantees ( invariants )
for an object of a class meant to cover moved from objects of that class ?

All of the choices which you have specified, which popularly boils down
to II or III, involves this question. The choice of II answers No to the
question above while the choice of III answers Yes to the question above.

But the issue is larger than this particular case and really needs
comment from someone who understands the C++ standard, rvalue
references, and moved objects beyond what is written in the C++ standard
document.

For instance I read in Lippman's "C++ Primer 5th Edition" that the only
things one should be able to do with a moved from object is destroy or
assign new values to it. This implies to me that a moved from object
should not really be used in any way unless one can repopulate its
values. IMO this supports the choice of II and that a guarantee for a
moved from object should no longer hold, since it is hopeless to use
that object unless one assigns something to it.

But perhaps Lippman's POV is not really that of the C++ standard
committee regarding the usefulness of moved from objects. Or perhaps,
despite the fact that the moved from object should not be used unless an
appropriate value(s) is reassigned to it, guarantees on a moved from
object should still hold. I really do not know, but it is important to
clarify what the disagreement is about and that it goes well beyond the
present case.


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