4

Say I have a union like this

union blah {
    foo f;
    bar b;
};

where both foo and bar are trivially copyable. Is it safe to do this:

blah b;
foo f;
memcpy(&b, &f, sizeof(f));

and then use b.f as the active union member? Or, do I have to memcpy to the particular union member, like this:

memcpy(&b.f, &f, sizeof(f));

The reason I'm concerned about this in practice is because I'm about to have to write a function that's roughly like this:

template<int c>
void init_union(blah& b, typename type_family<c>::type const& t) {
    switch (c) {
    case 0:
        memcpy(&b.p0, &t, sizeof(t));
        break;
    case 1:
        memcpy(&b.p1, &t, sizeof(t));
        break;
    // etc.
    }
}

but I would rather be able to skip the whole switch statement and just write this:

template<int c>
void init_union(blah& b, typename type_family<c>::type const& t) {
    memcpy(&b, &t, sizeof(t));
}
HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
jcarpenter2
  • 5,312
  • 4
  • 22
  • 49
  • You still may want the `switch` statement (or an equivalent) if there is a case where some values of `c` are not applicable. – quamrana Apr 18 '18 at 08:28
  • 1
    Possible duplicate of [memcpy/memmove to a union member, does this set the 'active' member?](https://stackoverflow.com/questions/39763548/memcpy-memmove-to-a-union-member-does-this-set-the-active-member) – llllllllll Apr 18 '18 at 08:31
  • @quamrana that is definitely true, but there are not in this case - the union has a member for each `type_family::type` that exists. – jcarpenter2 Apr 18 '18 at 08:33
  • @liliscent thanks but I don't think it is - if the answer to that question was "no" then the answer to this question would also be "no", but the answer to that question was "yes", and in that question they are copying into particular union members with `memcpy(&u.x_in_a_union` and `memcpy(u.a16`, not to the union itself. – jcarpenter2 Apr 18 '18 at 08:37

1 Answers1

0

It should be safe.

memcpy is safe as long as the type is trivially copyable, which applies to unions.

As long as only one of the members of the union is active, there should be no problem.

babu646
  • 989
  • 10
  • 22
  • 1
    But can `memcpy` change the active member if you copy to the entire union? – HolyBlackCat Apr 18 '18 at 08:31
  • Yes it can. The active member is "copied" along with the data. – babu646 Apr 18 '18 at 08:35
  • 2
    There is no active member we copy from... And we do not copy a foo into blah's foo, but into blah itself. Would this still implicitly activate blah.f? If so, fine, otherwise, undefined behaviour... – Aconcagua Apr 18 '18 at 08:55
  • I would probably just make a simple test program and check it. – babu646 Apr 18 '18 at 09:10
  • 3
    You cannot test for undefined behavior, as one of the possible results is "sometimes seem to work". – Bo Persson Apr 18 '18 at 11:52
  • If there is no active member then yes, it is undefined behaviour. Also, using uninitialized variables is strongly discouraged. An initialized union will always have an active member. Therefore, by avoiding uninitialized unions, you avoid undefined behaviour. – babu646 Apr 18 '18 at 12:52
  • I'm inclined to believe this is well, however I also agree with @HolyBlackCat's having added the `language-lawyer` tag; I need a more watertight argument that any standards-compliant compiler will accept this code than would be achieved by making a test program and trying it out. Larry Wall says Perl is an empirical science, and I treat C++ that way myself. But for the purposes of answering this question well for posterity I think a more formal answer referring to the spec or an authoritative website would be needed. Thanks though and I will be working under the assumption that this is true. – jcarpenter2 Apr 18 '18 at 23:29