C++ Logo

sg12

Advanced search

Re: [ub] Type punning to avoid copying

From: Gabriel Dos Reis <gdr_at_[hidden]>
Date: Fri, 26 Jul 2013 14:44:14 -0500
Howard Hinnant <howard.hinnant_at_[hidden]> writes:

| On Jul 26, 2013, at 2:35 PM, Jeffrey Yasskin <jyasskin_at_[hidden]> wrote:
|
| > Howard, if Gaby's right that new(&memory) int; leaves the object with
| > indeterminate value even if 'memory' started with a defined value (and
| > I think he is), then that's the rule you're breaking when you
| > explicitly change the active member of your union and then read the
| > new member.
|
| Ok, what if I change the active member this way:
|
| float InverseSquareRoot4(float x)
| {
| union U
| {
| float as_float;
| int32_t as_int;
| };
|
| U u = {x};
| // current member is as_float
| size_t active_member = 0;
| // temporary buffer
| alignas(U) char tmp[sizeof(U)];
| float xhalf = 0.5f*x;
| // Prepare to read from as_int
| if (active_member != 1)
| {
| std::memcpy(tmp, &u.as_float, sizeof(U));
| std::memcpy(&u.as_int, tmp, sizeof(U));
| active_member = 1;
| }
| // current member is as_int
| u.as_int = 0x5f3759df - (u.as_int>>1);
| // Prepare to read from as_float
| if (active_member != 0)
| {
| std::memcpy(tmp, &u.as_int, sizeof(U));
| std::memcpy(&u.as_float, tmp, sizeof(U));
| active_member = 0;
| }
| // current member is as_float
| u.as_float = u.as_float*(1.5f - xhalf*u.as_float*u.as_float);
| return u.as_float;
| }
|
| Howard

As I explained earlier, the real fundamental issue in this reformulation
(or the previous) is that there is no wording (as far as I can tell)
that allows to std::memcpy() from a non-int32_t object into an int32_t
and then consider that to be a definition or an initialization of the object:

      std::memcpy(&u.as_int, tmp, sizeof(U));

(I am not sure the alignmemt of 'tmp' is needed.)

-- Gaby

Received on 2013-07-26 21:44:29