How could one copy union simple members with memcpy?
Asked Answered
L

2

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?

Luciferin answered 26/8, 2019 at 7:45 Comment(7)
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.Silverts
Why? Why not just use =?Cothurnus
With named union member, you might do one memcpy.Krimmer
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?Downall
@Downall that's the trick, the class itself is a bit more complicated. Example piece shows just the problem.Luciferin
@Krimmer would it be standard- conforming to memcpy union as a whole class member?Luciferin
depends on type inside union, but in your case, yes.Krimmer
C
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.

Cottonweed answered 26/8, 2019 at 8:12 Comment(3)
Is memcpy'ed member considered "written"?Luciferin
@AlexanderG. Seems there's an open debate on the subject. https://mcmap.net/q/512030/-memcpy-memmove-to-a-union-member-does-this-set-the-39-active-39-member/10933809. You need a bookkeeping mechanism to know the active type or initialize one member first(so make it active) and then memcpyCottonweed
@AlexanderG. You may follow Jarod42 comment. Or if C++17 is an option use std::variant instead of union.Cottonweed
H
-2

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

Hectograph answered 26/8, 2019 at 8:1 Comment(2)
@Cottonweed I did not downvote, but this answer does not answer any of the questions OP asked.Ogdoad
@Ogdoad I agree it doesn't answer. But I believe leaving comment helps to improve postsCottonweed

© 2022 - 2024 — McMap. All rights reserved.