Boost logo

Boost :

Subject: Re: [boost] [variant] Please vote for behavior
From: Sebastian Redl (sebastian.redl_at_[hidden])
Date: 2013-02-02 10:57:59

On 02.02.2013, at 13:54, Edward Diener wrote:

> On 2/1/2013 9:32 PM, Jeffrey Lee Hellrung, Jr. wrote:
>> On Fri, Feb 1, 2013 at 5:51 PM, Edward Diener <eldiener_at_[hidden]>wrote:
>>> I agree with you but that means to me that for a class to be movable an
>>> invariant for that class can never be that the class cannot be empty.
>>> It seems to me that the Variant class does have an invariant which says
>>> that the class can never be empty. So my conclusion is that a Variant can
>>> not be movable.
>> Not true. First of all, the primary present issue is implementing move
>> semantics for a variant with recursive_wrapper. Non-recursive variants
>> aren't really a problem.
>> Second, specifically for recursive variants, if one of the underlying types
>> is default constructible (trivially, ideally!), then, again no issues (in
>> theory; such a solution isn't presently implemented). So we basically have
>> this very "narrow" case (recursive variant with no detectable
>> default-constructible types) which is the issue, and even then, we have a
>> solution (it's just, by all accounts, suboptimal, since it has to use new
>> sometimes).
> If you are going to be moving data from an object, but you must still recreate some of that data after the move so as not to leave the object empty, this does not seem to me to be a very successful move.

Anything that gives the target object the state the source object had and is cheaper than a copy is a successful move, really. That is what a move ultimately is: an optimization of copying.

> Perhaps we are in the land of "we say it is a 'move' but actually we are doing 'copying' of some of the data and moving the rest". Fair enough, but the gist of 'moving' as I understand it is that the moved from object is empty after the move even though the object still must be in a usable state.

No, the gist of 'moving' is that the target object has the source object' state, and the source object is fair game for anything as long as it is still valid. If it's more efficient to only copy some of the data rather than move it, then by all means do that. For example, look at the compiler-created move constructor for a simple data struct:

struct foo {
  std::string s;
  int i;

The move constructor will move the string, but just copy the int (because int makes no difference between copy and move). So the source object, after a move, will still have the same value in the int, but an empty string.

> I admit that I do not see in the current standard where a moved from object cannot still contain a copy of some of the data which has been moved from it, but I still would have thought that the concept of a movable object is that it is empty of its data after the move.

Consider what happens when you move an int. What does "empty of its data" even mean for an int (or any other POD)?
The requirement on moving in the standard is that the moved-from object has an arbitrary valid state. The move operations should therefore be written such that they move to the cheapest-possible valid state, and do it without throwing if at all possible.

For variant, this means that it should work this way:
0) If any contained type is not movable, the variant as a whole is not movable. If any contained type's move constructor is not nothrow, the variant's move constructor and assignment aren't either.
1) If the currently active type is not the recursion, move-construct that type in the target variant. Leave the source as-is otherwise.
2) If the active type is the recursion, then
2.1) if there is some type that is nothrow-default-constructible, give the pointer to the target variant, and default-contruct this type in the source,
2.2) if there is no such type, either be not movable, or be not nothrow-movable. I'm not sure which is the better choice here. But note that types that aren't nothrow-default-constructible are unlikely to be nothrow-move-constructible either, so see point 0.


Boost list run by bdawes at, gregod at, cpdaniel at, john at