2

Consider the following code fragment, assuming that A and B are both trivial types of the same size, say int64_t and double, or something similar:

union Punner {
  A x;
  B y;
};

Punner copy(Punner in)
{
  return in;
}

A pun(B in)
{
  Punner temp;
  temp.y = in;
  return copy(temp).x;
}

While I know that the line temp.y = in starts the lifettime of the y member of temp and reading temp.x would be undefined, when I get a new copy of the Punner type from the copy function, should it be assumed that the copy's y member's lifetime is also already started, and reading the copy's x member still undefined, or is it simply unspecified, and after obtaining the copy, I may actually read from either the x or y freely (in this case reading from x)?

I know that my question is similar in some ways to this one, but regretfully I was not able to confidently determine a precise answer to my question from the responses to it.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
markt1964
  • 2,638
  • 2
  • 22
  • 54

1 Answers1

1

You should think about what is actually happening in the memory.

Punner temp; //data in memory could be anything

temp.y = in; //data contains 8 bytes that describe an integer with the value in

copy(temp); //the copied data is 8 bytes that describe an integer with the value in

copy(temp).x; //accessing those 8 bytes as if they describe a double : getting giberish.
iliar
  • 932
  • 6
  • 11
  • Obviously the number coming back will be giberish, but I'm asking if the results are unspecified or undefined. – markt1964 Nov 22 '19 at 23:59
  • Yes I meant 8. What do you mean if it's unspecified or undefined? The two seem like synonyms. I described to you what will actually happen in the memory for any compiler I'm aware of. – iliar Nov 23 '19 at 00:00
  • @markt1964 in some cases I actually used it to access bits of a floating point number for converting them directly to fixed point numbers. – iliar Nov 23 '19 at 00:00
  • 3
    They aren't entirely synonyms. Undefined behavior is something that is supposed to be avoided at all times, but unspecified behavior will not necessarily be bad, the results just aren't specified. – markt1964 Nov 23 '19 at 00:01
  • @markt1964 I think both imply getting giberish. You can never get a blue screen, because the memory is allocated. Although, the compiler may generate some optimizations in case you have one field that's 4 bytes and another that's 16 and the compiler only sees assignment to the 4 bytes. But since it does see access to the 16 bytes, I guess it wouldn't optimize it that way. – iliar Nov 23 '19 at 00:03
  • 2
    I was specifically considering only the cases where A and B have the exact same size. Obviously if they are of different sizes, it would be all kinds of bad. Also, "Undefined behavior" is allowed to cause a crash. It might not, but it may. Unspecified behavior is simply that - unspecified. In my case, I'm asking which member, `x` or `y` happens to be awake in the return from `copy`? Or is it unspecified? – markt1964 Nov 23 '19 at 00:07
  • @markt1964 In that case, it's certainly `y`. Accessing `y` is clearly correct. `x` is the one that's undefined / unspecified. – iliar Nov 23 '19 at 00:11
  • @iliar [Unspecified and undefined are very different](https://stackoverflow.com/questions/2397984/undefined-unspecified-and-implementation-defined-behavior) and reading a union member that is not active causes undefined behavior, so the compiler is free to let the program crash or do whatever it wants it to. Doing this to type-pun floats to integers is also UB in C++. It may work because your compiler makes this extra guarantee, but no C++ compiler is required to behave as expected when doing this. – walnut Nov 23 '19 at 01:17
  • 1
    But I was asking if one has a fresh copy of a union that has been copied from somewhere else, is the "active member" explcitly defined to always be the same as the union it was copied from, or is it just unspecified? – markt1964 Nov 25 '19 at 16:42
  • @markt1964 yes it is defined to be the same active member as the union it was copied from. It is perfectly legal c/c++. – iliar Nov 25 '19 at 20:38
  • @markt1964 In fact, that is the reason for the constraints on a union having members with non trivial constructors. see: https://en.cppreference.com/w/cpp/language/union – iliar Nov 25 '19 at 20:45
  • @iliar No that is not well-defined even in C++17 (even though it is cleary supposed to be as you say), which is why the current most recent draft you can find online has added additional wording clarifying that the implicit copy constructor actually begins the lifetime of the correct active member. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0593r5.html#union-copies – JMC Sep 05 '20 at 23:53