I know this is a pretty common subject, but as much as the typical UB is easy to find, I did not find this variant so far.
So, I am trying to formally introduce Pixel objects while avoiding an actual copy of the data.
Is this valid?
struct Pixel {
uint8_t red;
uint8_t green;
uint8_t blue;
uint8_t alpha;
};
static_assert(std::is_trivial_v<Pixel>);
Pixel* promote(std::byte* data, std::size_t count)
{
Pixel * const result = reinterpret_cast<Pixel*>(data);
while (count-- > 0) {
new (data) Pixel{
std::to_integer<uint8_t>(data[0]),
std::to_integer<uint8_t>(data[1]),
std::to_integer<uint8_t>(data[2]),
std::to_integer<uint8_t>(data[3])
};
data += sizeof(Pixel);
}
return result; // throw in a std::launder? I believe it is not mandatory here.
}
Expected use pattern, heavily simplified:
std::byte * buffer = getSomeImageData();
auto pixels = promote(buffer, 800*600);
// manipulate pixel data
More specifically:
Pixel types can it be extended? (relaxing the is_trivial restriction? pixel with only 3 components?).Both clang and gcc optimize out the whole loop to nothingness, which is what I want. Now, I'd like to know whether this violates some C++ rules or not.
Godbolt link if you want to play around with it.
(note: I did not tag c++17 despite std::byte, because the question holds using char)
It is undefined behavior to use the result of promote as an array. If we look at [expr.add]/4.2 we have
Otherwise, if
Ppoints to an array elementiof an array objectxwithnelements ([dcl.array]), the expressionsP + JandJ + P(whereJhas the valuej) point to the (possibly-hypothetical) array elementi+jofxif0≤i+j≤nand the expressionP - Jpoints to the (possibly-hypothetical) array elementi−jofxif0≤i−j≤n.
we see that it requires the pointer to actually point to an array object. You don't actually have an array object though. You have a pointer to a single Pixel that just happens to have other Pixels following it in contiguous memory. That means the only element you can actually access is the first element. Trying to access anything else would be undefined behavior because you are past the end of the valid domain for the pointer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With