ฉันรู้ว่านี่เป็นเรื่องที่ค่อนข้างทั่วไป แต่เท่าที่ UB ทั่วไปหาได้ง่ายฉันไม่พบตัวแปรนี้จนถึงตอนนี้
ดังนั้นฉันจึงพยายามแนะนำวัตถุพิกเซลอย่างเป็นทางการในขณะที่หลีกเลี่ยงการคัดลอกข้อมูลจริง
ถูกต้องหรือไม่
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? pixel ด้วย 3 องค์ประกอบเท่านั้น)
เสียงดังกราวและจีซีซีทำให้ทั้งวงนั้นกลายเป็นความว่างเปล่าซึ่งเป็นสิ่งที่ฉันต้องการ ตอนนี้ฉันอยากรู้ว่านี่เป็นการละเมิดกฎ C ++ หรือไม่
ลิงค์ Godboltหากคุณต้องการเล่นกับมัน
(หมายเหตุ: ฉันไม่ได้ติดแท็ก c ++ 17 แม้ว่าจะstd::byte
เป็นเพราะคำถามยังคงใช้อยู่char
)
pixels[some_index]
หรือ*(pixels + something)
? นั่นจะเป็น UB
pixels
(P) ไม่ได้เป็นตัวชี้ไปยังวัตถุอาร์เรย์ Pixel
แต่ชี้ให้เป็นหนึ่งเดียว นั่นหมายความว่าคุณสามารถเข้าถึงได้pixels[0]
ตามกฎหมายเท่านั้น
Pixel
s ที่อยู่ติดกันใหม่ยังคงไม่ได้เป็นอาร์เรย์ของPixel
s