10

I'm not quite sure about standard quotes about memcpy and union trivial members.

Consider the code:

struct Test{
    union
    {
        void(*function_p)(void*);
        void(*function_p_c)(const void*);
    };
    Test(const Test &other)
    {
        using std::memcpy;
        memcpy(&function_p, &other.function_p, sizeof(function_p)); //?
        memcpy(&function_p_c, &other.function_p_c, sizeof(function_p_c)); //??
    }
};

int main(void)
{
    Test t1; t1.function_p = NULL; //let it be NULL for c++98 sake
    Test t2(t1); // is it safe? does this set new active member of union?

    return 0;
}

So the one question leads to another:

  • is code above safe? or is it UB with second/first memcpy depending on which union member user have touched? is it overkill to call memcpy for both members?

  • if it is not safe then how could I implement copy constructor without some flag-of-active-union-member?

timrau
  • 22,578
  • 4
  • 51
  • 64
Alexander G.
  • 457
  • 2
  • 14
  • 1
    Note: I just added the `language-lawyer` tag, which is customary for this kind of question. Since there's a max of five tags, I picked `std` to remove for that. – Ulrich Eckhardt Aug 26 '19 at 07:57
  • 3
    Why? Why not just use `=`? – user207421 Aug 26 '19 at 08:00
  • 1
    With named union member, you might do one `memcpy`. – Jarod42 Aug 26 '19 at 08:17
  • Or create two classes `TestA` and `TestB`, one with a member `function_p` and the other one with `function_p_c` instead. - You say that you want to do it "without some flag-of-active-union-member". If you don't have that kind of flag, how are you going to *use* the correct funtion pointer at other places in the class? – JimmyB Aug 26 '19 at 10:01
  • @JimmyB that's the trick, the class itself is a bit more complicated. Example piece shows just the problem. – Alexander G. Aug 26 '19 at 13:45
  • @Jarod42 would it be standard- conforming to memcpy union as a whole class member? – Alexander G. Aug 26 '19 at 13:51
  • 1
    depends on type inside union, but in your case, yes. – Jarod42 Aug 26 '19 at 14:27

2 Answers2

5

What you are doing with two memcpy is undefined behavior.

The union is only as big as necessary to hold its largest data member. The other data members are allocated in the same bytes as part of that largest member. The details of that allocation are implementation-defined, and it's undefined behavior to read from the member of the union that wasn't most recently written. Many compilers implement, as a non-standard language extension, the ability to read inactive members of a union.

other has only function_p as active and the second memcopy triggers undefined behavior.

Oblivion
  • 7,176
  • 2
  • 14
  • 33
  • Is memcpy'ed member considered "written"? – Alexander G. Aug 26 '19 at 13:47
  • @AlexanderG. Seems there's an open debate on the subject. https://stackoverflow.com/q/39763548/10933809. You need a bookkeeping mechanism to know the active type or initialize one member first(so make it active) and then memcpy – Oblivion Aug 26 '19 at 15:45
  • @AlexanderG. You may follow Jarod42 comment. Or if C++17 is an option use std::variant instead of union. – Oblivion Aug 26 '19 at 16:33
-2

Since both union members occupy the same space in memory, the second memcpy will overwrite the first.

U. W.
  • 414
  • 2
  • 10