Boost logo

Boost :

Subject: Re: [boost] [interest] underlying type library
From: Julian Gonggrijp (j.gonggrijp_at_[hidden])
Date: 2011-08-22 07:04:34


Eric Niebler wrote:

> [...] However, I might prefer a more
> conservative approach whereby users must opt-in to the memcpy
> implementation instead of making it the default.

In fact I arrived at this same conclusion after I realised the bitwise
approach was not as general as I thought. The library documentation
should contain some lines like the following in its introduction:

"In the general case, the user of this library will provide template
specializations of underlying_type_traits and move_raw. Their type can
then take advantage of algorithms that use the move_raw mechanism.

As a special case, if you are sure that your type does not depend on
the memory location of an object for the validity of its value (see
notes below), you can opt-in for the included bitwise implementation.
In that case you get move_raw and the underlying type basically for
free."

After which the "notes below" would provide a thorough explanation on
how to recognize problematic types.

Nevin Liber wrote:

> How often is this thing needed? The only times you need this is when the
> compiler generated move constructor/assignment operators either are deleted
> or are doing the wrong thing. Is that really the time you don't want people
> thinking about how to correctly write swap (or better, just write the
> correct move constructor and assignment operator).

How about compilers that don't generate move constructors and move
assignments at all because they don't support them? And what about
types for which move_raw is more efficient than source-validity-
preserving move (i.e. any type with a nontrivial default constructor)?

> Even examining the implementation for all your member variables isn't
> enough. The boost::function which holds a boost::bind(..., this, ...) where
> the function object is stored inside the boost::function object itself may
> now exhibit different semantics than when the function object it is holding
> is in the heap. Ugh.

Users should simply be warned that if their type has member data that
were implemented by a third party and which are initialized with a
pointer to (a part of) the main object, they should assume their type
to depend on the object's memory location for its validity.

> Way back when, C++ did bitwise copying for the compiler generated copy
> operations, and was changed to member wise copying for good reason. I
> really don't want to go back to that world.

Let me reassure you that move_raw is not inherently about bitwise
copying; you can do exactly the same with memberwise copying but that
requires the author of the type to provide their own implementation.

> The problem is, you are adding in a dependency on the *implementation*, not
> the interface of objects. Consider:
>
> struct W
> {
> X x;
> Y y;
> Z z;
> };
>
> 1. What are the requirements on implementations of X, Y and Z? Is
> trivially copyable enough? How about trivially copyable and isn't moveable
> (unless you want to second guess the move constructor)? Of course, if it is
> trivially copyable and not moveable, there is probably a reason...

The requirement is that it would be meaningful for W to be moveable,
and hence the same must apply to X, Y an Z. I'm assuming that users
are not interested in move_raw if value-permuting algorithms like swap
make no sense for their type.

Note that copying is a special case of moving; if copying makes sense
for a type and the type is mutable, then move_raw also makes sense. I
don't see how a type could be mutable and trivially copyable but not
moveable, except for a sheer lack of implementation of move operators.

> 2.. How are you going to enforce that?

I don't feel obliged to enforce this. If users insist on trying to
move around values which are immutable or non-movable, they have my
blessing.

Sebastian Redl wrote:

> On 21.08.2011 21:23, Julian Gonggrijp wrote:
>> Dear all,
>>
>> I think the set of types with which bitwise move_raw will yield
>> undefined behaviour can be sharply defined:
> The standard already does. Undefined behavior is a notion of the standard, not of a particular implementation. The standard says that this technique works only for PODs (trivially copyable types in 0x), nothing else.

Doesn't the standard say that bitwise copying of non-PODs is undefined
behaviour /because there are cases where bitwise copying will give you
an invalid result/? Have we not identified the cases for which an
invalid result will be obtained? Can we therefore not maintain --
making use of the semantical definition of move_raw and restricting
ourselves to the set of unproblematic types -- that bitwise copying is
a safe implementation of move_raw even though in a very strict
juridical sense it may be undefined behaviour?

>>> There is no such thing as an underlying type.
>> It's impossible to realise in current C++, but conceptually it exists.
>>
> Conceptually, if you think of classes as "aggregates and then some", there is the underlying aggregate.

I'm not thinking of classes in that way. The underlying type is
something different from an "underlying aggregate" (although I realise
I have given that impression in my first email; my apologies).
Instead, the underlying type is defined by its semantic relation to
the 'overlying type' as I have also stated in my reply to Mathias
Gaunard (http://lists.boost.org/Archives/boost/2011/08/184913.php):

The underlying type of T is a POD which can store the state of an
instance of T.

So far, it seems that those who have read Stepanov's paper are more
positive about the possible value of my proposal than those who didn't
read it. This seems to confirm that Stepanov is still better at
explaining the value of move_raw than I am.

Therefore I invite those who haven't read the paper yet to still do
so. Only lectures 4 and 5 are required; it's only 11 pages with some
trailing source code that you can skip. It's a very enjoyable read and
I almost dare to promise you that you'll want to read the rest of the
paper as well. :-)

The URL: http://www.stepanovpapers.com/notes.pdf

(If you happen to find something inside the paper that was missing in
my own argumentation so far, please let me know; such feedback would
be invaluable for future documentation of an underlying type library.)

-Julian


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