これはかなり一般的なテーマであることは知っていますが、典型的なUBを見つけるのは簡単ですが、今のところこの亜種は見つかりませんでした。
そこで、実際のデータのコピーを避けながら、Pixelオブジェクトを正式に紹介しようとしています。
これは有効ですか?
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.
}
予想される使用パターン、大幅に簡略化:
std::byte * buffer = getSomeImageData();
auto pixels = promote(buffer, 800*600);
// manipulate pixel data
すなわち:
- このコードには明確に定義された動作がありますか?
- はいの場合、返されたポインタを使用しても安全ですか?
- はいの場合、他のどの
Pixel
タイプに拡張できますか?(is_trivial制限を緩和?3つのコンポーネントのみを持つピクセル?)
clangとgccの両方がループ全体を無に最適化します。これが私が望んでいることです。さて、これがいくつかのC ++ルールに違反しているかどうか知りたいのですが。
(注:std::byte
質問はを使用しているため、にもかかわらずc ++ 17にタグを付けませんでしたchar
)
pixels[some_index]
か*(pixels + something)
?それはUBです。
pixels
(P)は配列オブジェクトへのポインターではなく、単一のへのポインターPixel
です。つまり、pixels[0]
合法的にしかアクセスできません。
Pixel
新しく配置された連続するは、まだの配列ではありませんPixel
。