C++ Logo

SG12

Advanced search

Subject: Re: [ub] data overlays: reinterpret_cast vs placement new
From: Johannes Schaub (schaub.johannes_at_[hidden])
Date: 2014-03-23 08:48:36


David Krauss wrote:

>
> On 2014–03–20, at 5:25 AM, Jens Maurer <Jens.Maurer_at_[hidden]> wrote:
>
>> On 03/18/2014 06:06 AM, David Krauss wrote:
>>> uint32_t datum = * (net_word< uint32_t > *) buf_ptr;
>>
>> What's "buf_ptr”?
>
> A blob of data with no dynamic type. It’s supposed to be idiomatic,
> cast-happy C using a memory overlay struct.
>

The Standard is not exceptionally clear what the difference between an
object whose lifetime hasn't started yet and an object that doesn't exist at
all is. As far as I am aware, such a difference only exists for class type
objects (during destruction and construction in constructors and
destructors).

In your case there was no construction of the class type
"net_word<uint32_t>", therefor lifetime could not start. Hence I think that
3.8p6 applies which renders your program undefined because " the glvalue is
used to access a non-static data member or call a non-static member function
of the object, or" (you are calling a conversion function).

Regarding the start of lifetime of the net_word object, i think the lifetime
begins when you complete the invocation of the constructor of "net_word<
uint32_t >". 3.8p1 says something else, but it has previously been shown
that this rule is defective (because it allows infinitely many objects whose
sizeof and alignments are compatible be at the same memory location at the
same time). Therefor I assume that this paragraph still does not reflect the
actual intent, for types like int and float but also for class types with
trivial constructors.

>>> Is it any safer to jump through a little hoop with placement new?
>>>
>>> uint32_t datum = * new( buf_ptr ) net_word< uint32_t >;
>>
>> This destroys the previous contents of *buf_ptr, from a
>> specification point-of-view.
>
> It runs the constructor of a trivially-constructible class, which does
> nothing and has no particular significance. The object lifetime already
> began when “storage with the proper alignment and size for type T is
> obtained,” which occurred when the data blob was allocated.
>

Your code renders the value of the data member array indeterminate, by
5.3.1p17 (default initialization happens), 12.6.2p8 (the member array is
default initialized), 5.3.4p1 (storage duration is dynamic) and 8.5p12 (the
member array has indeterminate value).

I'm not sure what rule to apply to infer that when memcpy'ing that array
into a uint32_t, that this uint32_t then also contains an undeterminate
value. The paragraphs 3.9p2 and 3.9p3 both assume that you previously had
another uint32_t object that you grabbed the bytes from that make up the
array.

In case nothing else covers it yet, should 3.9p2 say that when the array has
an indeterminate value (disregarding of whether the array has been copied to
from another object), that the target object copied to also has an
indeterminate value?


SG12 list run by herb.sutter at gmail.com