小编Soc*_*ras的帖子

如何在C++中正确访问映射内存而没有未定义的行为

我一直试图弄清楚如何从C++ 17访问映射缓冲区而不调用未定义的行为.对于这个例子,我将使用Vulkan的返回缓冲区vkMapMemory.

因此,根据N4659(最终的C++ 17工作草案),[intro.object]部分(重点补充):

C++程序中的构造创建,销毁,引用,访问和操作对象.一个目的是通过一种创建定义(6.1),通过一个 新的表达式 (8.3.4)中,当隐式地改变所述一个联合的活性部件(12.3),或当一个临时对象被创建(7.4,15.2).

显然,这些是创建C++对象的唯一有效方法.因此,假设我们得到一个void*指向主机可见(和相干)设备内存的映射区域的指针(当然,假设所有必需的参数都有有效值并且调用成功,并且返回的内存块足够大)正确对齐):

void* ptr{};
vkMapMemory(device, memory, offset, size, flags, &ptr);
assert(ptr != nullptr);
Run Code Online (Sandbox Code Playgroud)

现在,我希望将此内存作为float数组访问.显而易见的事情static_cast是指针并按照我的快乐方式继续如下:

volatile float* float_array = static_cast<volatile float*>(ptr);
Run Code Online (Sandbox Code Playgroud)

(volatile包含它因为它被映射为相干存储器,因此可以在任何时候由GPU写入).然而,在该存储器位置中技术上float不存在阵列,至少不是在引用的摘录的意义上,因此通过这样的指针访问存储器将是未定义的行为.因此,根据我的理解,我有两种选择:

1. memcpy数据

它应该总是能够使用本地缓存,将它转换为std::byte*memcpy表示到映射区域.GPU将按照着色器中的指示解释它(在这种情况下,作为32位数组float),从而解决了问题.但是,这需要额外的内存和额外的副本,所以我宁愿避免这种情况.

2.放置 - new阵列

看来,[new.delete.placement]部分没有对如何获得放置地址施加任何限制(无论实现的指针安全性如何,它都不必是安全派生的指针).因此,可以通过放置创建有效的浮点数组new,如下所示:

volatile …
Run Code Online (Sandbox Code Playgroud)

c++ volatile language-lawyer mapped-memory c++17

23
推荐指数
1
解决办法
906
查看次数

标签 统计

c++ ×1

c++17 ×1

language-lawyer ×1

mapped-memory ×1

volatile ×1