[ub] Type punning to avoid copying

Gabriel Dos Reis gdr at cs.tamu.edu
Fri Jul 26 21:44:14 CEST 2013


Howard Hinnant <howard.hinnant at gmail.com> writes:

| On Jul 26, 2013, at 2:35 PM, Jeffrey Yasskin <jyasskin at google.com> 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



More information about the ub mailing list