thorsan
thorsan

Reputation: 1064

Casting from basic type to non-POD struct

This question is whether casting a byte stream into a non-POD structure is undefined behaviour.

Where data is produced somewhere like this, i.e. packs 4 4-bit values into a short.

std::vector<unsigned short> v(50);
for(int i<0; k < 50; k++)
{
    v[k] = (k%8) | (k+1)%8 << 4 | (k+2)%8 << 8 | (k+2)%8 << 12
}

Then the data is passed to a second module as a byte stream and parsed in the receiving module.

struct Data
{
Data(unsigned short a, unsigned short b, unsigned short c, unsigned short d)
{
    value = (a & 0xF) | (b & 0xF) << 4 | (c & 0xF) << 8 | (d & 0xF) << 12
}

Data(unsigned short v) : value(v) {}

short getA() const
{
    return value & 0xF
}

short getB() const
{
    return (value >> 4) & 0xF
}

short getC() const
{
    return (value >> 8) & 0xF
}

short getD() const
{
    return (value >> 12) & 0xF
}

private:
    unsigned short value;
}

...

unsigned char* data = ...;
Data* ptr = reinterpret_cast<Data*>(data);

ptr[0].getA();

Is this undefined behaviour? The size of the struct Data is the same as short, but does the presence of a constructor and member functions make it UB? If I remove the constructors, will it then be fine?

Upvotes: 0

Views: 59

Answers (2)

YSC
YSC

Reputation: 40100

Yes it is. But you can find an easy alternative:

std::vector<unsigned short> in(50);
std::vector<Data> out{begin(in), end(in)};
(void) out[0].getA();

The construction of out will construct Data objects in-place from each element of in. And you can trust your compiler to optimize away any memory copy ;)

Upvotes: 0

Jesper Juhl
Jesper Juhl

Reputation: 31459

You have to go through a constructor to construct an object. You can't simply cast a byte stream and then pretend that it results in a usable object. For a trivially copyable type you can create the object first, then copy in bytes, but otherwise a constructor call is needed.

To answer your question: Yes, that would be UB.

Upvotes: 2

Related Questions