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
P
points to an array elementi
of an array objectx
withn
elements ([dcl.array]), the expressionsP + J
andJ + P
(whereJ
has the valuej
) point to the (possibly-hypothetical) array elementi+j
ofx
if0≤i+j≤n
and the expressionP - J
points to the (possibly-hypothetical) array elementi−j
ofx
if0≤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