Boost logo

Boost :

Subject: Re: [boost] [variant] Please vote for behavior
From: Dave Abrahams (dave_at_[hidden])
Date: 2013-01-27 11:12:13

on Sat Jan 26 2013, Neil Groves <> wrote:

> On Fri, Jan 25, 2013 at 11:58 PM, Dave Abrahams <dave_at_[hidden]> wrote:
>> on Fri Jan 25 2013, Neil Groves <> wrote:
>> >>
>> >> I think variant after move is like int without initialization:
>> >> int i;
>> >> cout << i; // don't do this
>> >> If the fact, that moved-from objects are only good for destruction or
>> >> assignment-to is accepted, then invariants for moved-from objects are
>> >> allowed to be violated.
>> >>
>> >>
>> > I completely agree with the notion that a moved-from object simply should
>> > not be used in any manner.
> Well, that's just wrong, for the non-destructive move model used by the
>> standard. The standard library relies on the ability to both assign
>> and destroy moved-from elements. If you want destructive move, that's a
>> whole research project. We on the committee who created rvalue
>> references couldn't figure out how to make it work.
> I think this comes down to my poor definition of use. I was thinking of
> "use" as apply public methods and mentally classifying assignment, copying,
> destruction as operations preparing objects for "use". I am somewhat
> confused about the move-from standardisation and will attempt to study this
> in more detail. My perception of this is that the object is in a rather new
> state and if I can't call public accessors and therefore their
> relationships no longer hold I think it could be argued that the
> class-invariants have been broken.

You could define it that way, but then you lose any power to use the
invariant to reason about program correctness. Again, for class
invariants to have any power, they have to never break except during
individual mutations.

The way you deal with this situation is to say that those "public
accessors" (or whatever) have preconditions that include "not in the
moved-from state."

>> > It is interestingly divergent from the typical Design by Contract
>> > idiom. It is much more usual, in my experience for the
>> > class-invariants to hold up to and including entry to the destructor
> I don't understand what any of that means.
> I'm sorry for not being clearer. From my understanding of DbC the
> class-invariants must hold upon entry and exit of public functions with the
> exceptions that the class-invariants may not hold upon entry into the
> constructors
> and upon exit of the destructor.

Yeah, well the object doesn't exist in those periods, so I just add
"during the object's lifetime" and the definition is complete.

> Since I can no longer operate upon the object after it has been moved

Who says you can no longer operate upon the object after it has been

> it seems we have a new "undefined state" that doesn't gel well with
> typical DbC application.

No, it's just a state. The moved-from state for std::vector is the same
as its empty state. You can do all the same things with it.

> As I stated previously I don't label this as bad. I label it as
> interesting.

It's not as interesting as you're making it out to be, or at least it
doesn't have to be. Creating "interesting" exceptions just makes it
harder to reason about code. There's a coherent point of view where the
usual definition of "invariant" holds, that fully describes the
situation. Why not adopt that point of view instead of changing the
meaning of "invariant?"

Incidentally, this is the same reason the basic exception-safety
guarantee doesn't say "the object needs to be destructible, but its
invariants don't necessarily hold." There's no need to say that
provided you correctly describe the invariant.

>> > If I understand correctly the standard is divergent
>> divergent from what?
> My experience of DbC with Eiffel, D. I was simply referring to the odd
> state of the object where it is still 'live' yet cannot have public
> functions called despite the caller meeting pre-conditions.

The state of the object in question is one of the preconditions. Can I
write v.front()? Not if the v is an empty container. There's no

> This seems to require an adjustment to the way one reasons about code
> albeit in a not particularly troublesome way.

Aù contraire, I would find that "adjustment" extremely troubling, which
is why I don't go there.

>> > to allow sensible compiler implementations of clean-up code for
>> > moved-from objects.
>> I don't understand what you're saying here, either.
> I think I'm probably wasting your time. I should probably attempt to
> improve my understanding of the currently specified move semantics.

IMO you should attempt to adopt a way of explaining those semantics to
yourself that doesn't require tearing asunder fundamental definitions,
like "invariant," upon which we rely to understand code. :-)

> I think while I do not understand the Rationale for allowing
> assignment and destruction of moved-from objects

Destruction is trivial to explain:

void f(bool q, X a)
    std::vector<X> v;
    if (q)
    // <=== What happens to a right here?

Remember that q and the set of things potentially moved-from can be
arbitrarily complex, so although the above example could be handled
easily in a compiler's codegen, in general it can't.

The reasons for assignment are in part practical. The complexity of
vector::insert explodes when you support move semantics but can't assign
to moved-from elements. You need at least two implementations in that

> I am not in a position to make intelligent comments. I try to make
> that stop me from posting; sometimes I suffer the delusion that I
> actually understand things!

I think you're understanding move semantics, but you understand them in
a way that is harmful to your understanding of other things. I suggest
you pick an understanding that's consistent with the other theories. ;-)

Dave Abrahams
BoostPro Computing                  Software Development        Training             Clang/LLVM/EDG Compilers  C++  Boost

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