Can bit_cast do the same thing as memcpy to store a pointer into an array of shorts without undefined behaviour?

936 views Asked by At

While there might be an XY issue that led me here, I am curious about the limits of the new bit_cast in C++20, and this seems a good illustration of it.

Note that there is nothing inherently wrong with std::memcpy and it does not cause undefined behavior. It is also enough of an idiom to generally be optimized out to be the equivalent of a cast. The problem I have is that the intent of its usage is not as clear as it could be and it seems more C than C++.

How could you use bit_cast to do the same thing (without any undefined behavior) as the following:

#include <cstring>

void ptr2array(short (&x)[], int offset, const void * ptr)
{
    std::memcpy(&(x[offset]), ptr, sizeof(void *));
}

void array2ptr(void * & ptr, int offset, short (&x)[])
{
    std::memcpy(ptr, &(x[offset]), sizeof(void *));
}

Note that the following is fundamentally a no-op (tested here: https://godbolt.org/z/ce9Ecx8TG)

void * tst(void * orig)
{
    short x[101];
    int offset = 67;
    void * ret=orig;

    ptr2array(x, offset, ret);
    array2ptr(ret, offset, x);

    return ret;
}

Keep in mind that memcpy works fine with the misalignment (using offset).

Also requiring an array of shorts, as opposed to char, avoids some of the leniencies with char, but keeps the alignment issues.

1

There are 1 answers

4
Nicol Bolas On

bit_cast is for doing conversions between objects. It creates a new object whose binary data comes from some other object. It doesn't work on language arrays because, while they are objects, they don't work like objects. You can't pass them around the same way you can other objects. They decay to pointers, you can't return arrays, etc.

You can bit_cast with std::array and similar types, but even those are potentially a problem. std::array<char, sizeof(void*)> for example is not required to have the size of a void*. And bit_cast only works if the source and destination objects have the same size.

bit_cast also returns the object it creates. Which means you cannot (easily) bit_cast into existing storage. Nor is it easy to do a bit_cast from a range of bytes.

If you're trying to copy bits of data into storage... just do that. bit_cast isn't here to replace every use of memcpy.