C++ Logo

sg12

Advanced search

Re: [ub] Type punning to avoid copying

From: Richard Smith <richardsmith_at_[hidden]>
Date: Sun, 28 Jul 2013 13:50:33 -0700
On Sun, Jul 28, 2013 at 10:42 AM, Nevin Liber <nevin_at_[hidden]>wrote:

> On 28 July 2013 11:44, Gabriel Dos Reis <gdr_at_[hidden]> wrote:
>
>> We shouldn't be doing anything in rash.
>>
>
> Who is arguing for a rash decision? This sounds like a straw man to me.
>
> As far as I can tell, we are exploring how to meet this very real need of
> programs (efficiently turning a buffer of raw data into something which has
> structure), which is currently being met (either accidentally or
> deliberately) by relying on certain undefined behavior not being undefined
> in any practical sense.
>

FWIW, I don't agree that such code necessarily has undefined behavior.
Consider this ugly code, which is the kind of thing people have been
writing for years:

ALIGNED(16) char buffer[BUFFER_SIZE];
size_t buffer_pos, buffer_read;

T *get_from_network() {
  if (buffer_pos + sizeof(T) < buffer_read)
read_more_into_buffer(sizeof(T));
  assert(is_suitably_aligned_for<T>(buffer+buffer_pos));
  return (T*)buffer[buffer_pos];
}

Now, [basic.life]p1 says that, unless the object has non-trivial
initialization, its lifetime begins "when storage with the proper alignment
and size for type T is obtained". The wording here is circular, because we
don't know whether an object is being initialized until we know whether its
lifetime begins, and vice versa, but it can be argued that the lifetime of
a T object began *before* the data was copied into the buffer, because
storage with suitable size and alignment was obtained before that point.

More generally, my view of how the lifetime rules in [basic.life]p1 are
intended to work is:
 * If there exists a set of times when objects' lifetimes begin and end,
and that set gives the program defined behavior, then the program has
defined behavior
 * Otherwise, the program has undefined behavior

(In effect, the programmer chooses when lifetimes begin and end, and does
not need to write this intent in the source code.) Different choices of
lifetime beginning/end can only change whether the program has defined
behavior, and cannot imbue it with two different defined behaviors, so this
approach seems to be coherent, and (I think) captures what people expect.

(The [basic.life]p1 rules are also somewhat defective, because obtaining
storage of suitable size and alignment for an object of class type without
a trivial default constructor should not start the lifetime of such an
object, but if the object is not initialized, the relevant rule does not
apply.)

Received on 2013-07-28 22:50:34