gpt4 book ai didi

c++ - 类型双关主题的变体 : in-place trivial construction

转载 作者:行者123 更新时间:2023-12-02 05:19:03 25 4
gpt4 key购买 nike

我知道这是一个非常常见的主题,但尽管典型的 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++ 规则。

Godbolt link如果你想玩玩它。

(注意:尽管 std::byte,但我没有标记 c++17,因为使用 char 仍然存在问题)

最佳答案

promote的结果用作数组是未定义的行为。如果我们看 [expr.add]/4.2我们有

Otherwise, if P points to an array element i of an array object x with n elements ([dcl.array]), the expressions P + J and J + P (where J has the value j) point to the (possibly-hypothetical) array element i+j of x if 0≤i+j≤n and the expression P - J points to the (possibly-hypothetical) array element i−j of x if 0≤i−j≤n.

我们看到它需要指针实际指向一个数组对象。但实际上你并没有数组对象。您有一个指向单个 Pixel 的指针,而该像素恰好在连续内存中紧随其后有其他 Pixel。这意味着您实际可以访问的唯一元素是第一个元素。尝试访问其他任何内容将是未定义的行为,因为您已经超出了指针有效域的末尾。

关于c++ - 类型双关主题的变体 : in-place trivial construction,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59737794/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com