
On Tue, Jan 8, 2013 at 4:18 PM, Hartmut Kaiser <hartmut.kaiser@gmail.com> wrote:
On Tue, Jan 8, 2013 at 2:49 AM, Hartmut Kaiser <hartmut.kaiser@gmail.com> wrote:
On 1/8/13 4:14 AM, Paul Smith wrote:
A recursive_wrapper is not a pointer. It's a value-like wrapper that is assumed to always contain a valid object. The move constructor should leave the moved-from recursive_wrapper in a valid state, which precludes nullifying it. That is, unless you suggest adding an "empty" state to recursive_wrapper, which doesn't sound like a very good idea.
I disagree. That state will happen only when copying rvalues which will immediately be destructed anyway. What danger do you see in that situation? Example:
recursive_wrapper<foo> bar() {...} // function returning recursive_wrapper
recursive_wrapper<foo> foo(bar()); // copy
Under no circumstances will anyone get to see that "empty" state. Do you see something that I don't?
Without this move optimization (as it currently is), it is very inefficient especially with big structures (e.g. tuples and fusion adapted structs). Without this optimization, such temporary copies will end up with two heap allocations and unnecessary copying of the structures, instead of one heap allocation and a simple pointer swap. That would mean the missed optimization in the order of magnitudes with applications that use variant heavily (e.g. Spirit).
I agree 100% with Joel. Move construction means move construction - i.e. the source object is by definition left in a zombie state. No harm done. What's the point in having a move constructor which essentially is equivalent to a copy constructor in the first place?
Because it's not equivalent to a copy constructor. I can mutate the source object, just not break it.
I did not suggest breaking the object. Setting the pointer to zero still leaves the object in valid state, no?
No.
And if not, it is easy enough to make it a valid state by changing the implementation.
Sure, it's easy enough to add an empty state. The problem is that now everything that uses recursive_wrapper must take into account that it may not contain a live value.
The move-ctor of std::vector is much more efficient than the copy-ctor, even though it leaves the source as a completely valid vector. Even in the recursive_wrapper case, the move-ctor is still (potentially) more efficient than the copy-ctor.
The only thing the standard requires wrt a moved-from object is that they are left in a valid (although unspecified) state. Thus simply nulling out the pointer in the reference_wrapper should do the trick (just as Joel proposed).
See for instance: 17.6.5.15 - [lib.types.movedfrom]
<quote> Objects of types defined in the C++ standard library may be moved from (12.8). Move operations may be explicitly specified or implicitly generated. Unless otherwise specified, such moved-from objects shall be placed in a valid but unspecified state. </quote>
I think you misinterpret the term "valid state" in this context. A valid state is one that doesn't break the invariants of the object. A recursive_wrapper is assumed to always contain an instance, hence clearing it's pointer is not a valid state. A "valid but unspecified state" simply means *any* valid state (e.g. it can contain a different value). Btw, these requirements are for the library types, not client types used in conjunction with them. For the equivalent requirements on client types see tables 20 and 22 which reiterate these requirements using clearer wording.
Regards Hartmut --------------- http://boost-spirit.com http://stellar.cct.lsu.edu
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- Paul Smith