我有以下使用指针算术的代码,并希望使用std::span
(或者,我想是gsl::span
(替换它。该代码在多个像素上迭代,每个像素由4个连续字节表示,并更新它们的蓝色和绿色。
auto* row = (uint8_t*)buffer->data;
for (auto y = 0; y < buffer->height; ++y) {
auto* pixel = (uint32_t*)row;
for (auto x = 0; x < buffer->width; ++x) {
auto blue = x + blueOffset;
auto green = y + greenOffset;
*pixel++ = ((green << 8) | blue);
}
row += buffer->pitch;
}
buffer->data
是从对WindowsVirtualAlloc(...)
函数的调用返回的void*
。
如何按照C++核心指南和Moderns C++的建议,编写此代码以使用安全、现代的C++,如std::span
?
这与C++20、gsl和gsl-lite中的每一个一起编译。由于您没有提供可复制的示例,我没有测试或基准测试此解决方案。
auto const my_span = span{
reinterpret_cast<uint8_t *>(buffer->data),
buffer->height * buffer->pitch};
constexpr auto size_ratio = sizeof(uint32_t) / sizeof(uint8_t); // 4
auto const uint8_width = size_ratio * buffer->width;
auto row_offset = 0UL;
auto row = my_span.subspan(row_offset, buffer->width);
for (auto y = 0; y < buffer->height; ++y) {
auto const pixels = span{
reinterpret_cast<uint32_t *>(row.data()),
buffer->width};
auto pixel = pixels.begin();
for (auto x = 0; x < buffer->width; ++x) {
auto const blue = x + blueOffset;
auto const green = y + greenOffset;
*pixel++ = ((green << 8) | blue);
}
row_offset += buffer->pitch;
row = my_span.subspan(row_offset, uint8_width);
}
显然,由于将相同的内存解释为uint8_t
和uint32_t
,因此在这里使用跨度并不一定会使代码更容易读取。跨度仍然应该提供更多的安全性。
通过在buffer
所指向的结构中提供更多的成员或成员函数,可以使代码更容易阅读。例如,成员函数可以为您提供所需的子扫描,或者至少提供uint8_width
。由于没有人问我,我没有碰这里的结构。它可能是由库提供的,但在这种情况下仍然可以编写包装器。