C++ Logo

SG12

Advanced search

Subject: Re: [ub] type punning through congruent base class?
From: Herb Sutter (hsutter_at_[hidden])
Date: 2014-01-16 15:10:19


> > | > Well, as far as I understand, trivial constructors might not be called at all.
> > |
> > | Maybe "might not be called" is part of the bug then. Isn't the right
> > | model that trivial ctors are called, but "might do nothing"?
> >
> > Yes, agreed.
>
> That may be part of a proposed model, but it's not part of the existing model,
> which (for compatibility) is based on C's model, where fields of a (necessarily
> trivially-constructible) struct can be written to as soon as suitable memory for
> that struct is obtained.

Ah, I see the problem, thanks James and Daveed. Let me try to summarize what I've learned so far.

In C++, "storage" and "lifetime" don't mean the same thing for a non-trivially-constructible type.

But in C the word "lifetime" has a different meaning than C++. I have C99 handy, but it should be the same in C11, and "lifetime" and "storage duration" are the same thing in C:

        6.2.4/1: An object has a storage duration that determines its lifetime. There are three storage durations: static, automatic, and allocated. Allocated storage is described in 7.20.3.

        6.2.4/2: The lifetime of an object is the portion of program execution during which storage is guaranteed to be reserved for it.

        7.20.3: The order and contiguity of storage allocated by successive calls to the calloc, malloc, and realloc functions is unspecified. The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object and then used to access such an object or an array of such objects in the space allocated (until the space is explicitly deallocated). The lifetime of an allocated object extends from the allocation until the deallocation. Each such allocation shall yield a pointer to an object disjoint from any other object. The pointer returned points to the start (lowest byte address) of the allocated space.

But one thing that follows here is that in C, "the object" is the raw memory. Right? This follows from the above three quotes.

So is that different in C++? As Daveed pointed out:

> > Am I missing something?
>
> I think so: 3.8/1 also says that the lifetime of an object ends if its storage is
> reused

"...or released" -- okay. I always thought reused meant deallocated and reallocated, but since it says "reused or released" it does seem to follow that reused means what Daveed said:

> . So when you write to *ps, you've terminated the lifetime of *pb.

OK, that's C++. The word "reused" doesn't appear anywhere in the C99 standard at least.

Trying to summarize:

So was the goal of the 3.8/1 wording of "reuse" to acknowledge (and be compatible with) the C memory-scribbling, while still being able to say that even for raw storage and PODs a given piece of storage has a well-defined type at any given point in time (namely the one it was last written to as)? And does "reused" clearly say that "written-to" part if that's the intent?

And so for raw memory and PODs, storage as a type T begins when you read or write it as a T, and ends when you read or write as some other type U, as long as T and U are PODs that fit in the storage (incl. size and alignment)?

And dare I ask: Um, what about using part of the same allocated buffer to hold a T and another part to hold a U, such as malloc(1000) and read/write an int at offset 10 and read/write a short at offset 314 -- they're the same allocation, so do we even have any way to talk about that?

Herb


SG12 list run by herb.sutter at gmail.com