Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/132.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在C++;有动态校准要求吗? < C++中正确分配和使用具有动态指定对齐方式的缓冲区的正确方法是什么?我想到的用例是Vulkan dynamic uniform buffers(请参见在摘要中讨论所需过程的部分),对于该用例,对齐约束是通过VkPhysicalDeviceLimits上的MinuniformBufferofSetAlignment属性给出的,这在编译时是未知的_C++_Memory Management_C++17 - Fatal编程技术网

如何在C++;有动态校准要求吗? < C++中正确分配和使用具有动态指定对齐方式的缓冲区的正确方法是什么?我想到的用例是Vulkan dynamic uniform buffers(请参见在摘要中讨论所需过程的部分),对于该用例,对齐约束是通过VkPhysicalDeviceLimits上的MinuniformBufferofSetAlignment属性给出的,这在编译时是未知的

如何在C++;有动态校准要求吗? < C++中正确分配和使用具有动态指定对齐方式的缓冲区的正确方法是什么?我想到的用例是Vulkan dynamic uniform buffers(请参见在摘要中讨论所需过程的部分),对于该用例,对齐约束是通过VkPhysicalDeviceLimits上的MinuniformBufferofSetAlignment属性给出的,这在编译时是未知的,c++,memory-management,c++17,C++,Memory Management,C++17,我最初认为我可能能够使用操作符new(std::align\u val\t)执行以下操作 Foo* buffer = new(std::align_val_t{alignment}) Foo[n]; 但这并不能编译(至少在MSVC上是这样) 我还观看了Timur Doumler的CppCon演示文稿“”,其中指出,对像std::aligned\u alloc这样的结果使用重新解释强制转换,会导致未定义的行为 到目前为止,我已经得出以下结论: std::size_t n = getNumberO

我最初认为我可能能够使用
操作符new(std::align\u val\t)
执行以下操作

Foo* buffer = new(std::align_val_t{alignment}) Foo[n];
但这并不能编译(至少在MSVC上是这样)

我还观看了Timur Doumler的CppCon演示文稿“”,其中指出,对像
std::aligned\u alloc
这样的结果使用
重新解释强制转换
,会导致未定义的行为

到目前为止,我已经得出以下结论:

std::size_t n = getNumberOfElements(); // possibly not known at compile time
std::size_t alignment = getRequiredAlignment(); // not known at compile time

makeSureMultiplicationDoesNotOverflow(sizeof(Foo), n); // details irrelevant

void* storage = std::aligned_alloc(sizeof(Foo) * n, alignment); // _aligned_malloc on MSVC
if (!storage) { std::terminate(); }
Foo* buffer = new(storage) Foo[n];

// do stuff with buffer

for(std::size_t i = 0; i < n; ++i) { buffer[i].~Foo(); }
std::free(storage); // _aligned_free on MSVC
auto storage = static_cast<Foo*>(std::aligned_alloc(n * sizeof(Foo), alignment));
std::uninitialized_default_construct_n(storage, n);
auto ptr = std::launder(storage);

// use ptr to refer to Foo objects

std::destroy_n(storage, n);
free(storage);
std::size\u t n=getNumberOfElements();//在编译时可能不知道
std::size_t alignment=getRequiredAlignment();//在编译时不知道
确保乘法不超过(sizeof(Foo),n);//细节无关
void*storage=std::aligned_alloc(sizeof(Foo)*n,alignment);//_在MSVC上对齐\u malloc
如果(!存储){std::terminate();}
Foo*buffer=新(存储)Foo[n];
//用缓冲区做东西
对于(std::size_t i=0;i
我是否错过了一些会导致未定义行为的东西

编辑:我注意到上面没有将对齐应用于除第一个对象之外的任何对象,所以这绝对是一个oops


(显然,在实际应用程序中,应该将其封装到一个类中以提供RAII,但暂时不要这样做,以免使示例代码膨胀。)

您可以执行以下操作:

std::size_t n = getNumberOfElements(); // possibly not known at compile time
std::size_t alignment = getRequiredAlignment(); // not known at compile time

makeSureMultiplicationDoesNotOverflow(sizeof(Foo), n); // details irrelevant

void* storage = std::aligned_alloc(sizeof(Foo) * n, alignment); // _aligned_malloc on MSVC
if (!storage) { std::terminate(); }
Foo* buffer = new(storage) Foo[n];

// do stuff with buffer

for(std::size_t i = 0; i < n; ++i) { buffer[i].~Foo(); }
std::free(storage); // _aligned_free on MSVC
auto storage = static_cast<Foo*>(std::aligned_alloc(n * sizeof(Foo), alignment));
std::uninitialized_default_construct_n(storage, n);
auto ptr = std::launder(storage);

// use ptr to refer to Foo objects

std::destroy_n(storage, n);
free(storage);
auto storage=static_cast(标准::aligned_alloc(n*sizeof(Foo),alignment));
std::未初始化的\u默认\u构造\u n(存储,n);
自动ptr=标准::流槽(存储);
//使用ptr引用Foo对象
标准::销毁n(存储,n);
免费(储存);
std::aligned_alloc
返回的指针强制转换为
Foo*
不是未定义的行为。如果您尝试在创建
Foo
对象之前的
std::aligned\u alloc
之后立即取消对它的引用,那么它将是UB

编辑。

上面的代码在技术上是未定义的行为。但是在C++中,没有UB的100%种标准一致的分配方式。从实用的角度来看,本规范是可靠和安全的<代码>标准::流槽(存储)
可能应用于通过
存储
指针访问
Foo
对象


有关详细信息和讨论,请参阅。

您已经有了一个更好的答案,但我只想补充一点,您的代码具有未定义的行为

new
的数组形式,甚至是您正在使用的placement new形式,都允许使用分配中未指定数量的内存来存储运行时的元数据(例如,
delete[]
的分配大小,以了解需要销毁多少元素)

因此,您无法保证分配的内存大小足够,也无法保证新位置返回的数组的实际指针正确对齐


从目前的草稿中我可以看出,这似乎在C++20中有所改变,使得数组放置的这种特殊用法表现良好,但在C++17或更早的版本中并不要求如此。

我看到的唯一一件事是没有检查
存储==nullptr
的返回。请注意,至少根据我的理解,Vulkan中的minuniformbufferofsetalignment与GPU上统一缓冲区的对齐有关。因此,
minuniformbufferfetaalignment
只是关于如何从更大的缓冲区资源分配统一的缓冲区,这只涉及
VkDeviceSize
类型的整数上的偏移量的计算。CPU端的源数据对齐不应受到影响!?Afaik
sizeof(Foo[n])
将是一个编译时常量(请参阅),因此它实际上不能解释
n
…@MaxLanghof的动态值-很好的一点是,我将示例从本地代码中翻译出来,我在那里有常量。我将修复这个问题和错误检查,因为这些不是我真正感兴趣的问题。@MichaelKenzel-是的,这让我有点困惑。我认为要求是GPU端,但这也使用了主机端数据的对齐。然而,即使Vulkan没有必要这样做,我仍然会从纯理论的角度对如何这样做感兴趣。VLA的优点是,这是我在将代码从本地环境重新排列到SO网站时引入的一个愚蠢错误。@antispinwards,这是我现在正在思考的问题<代码>标准::未初始化的\u默认\u构造\u n使用
存储
中的新位置构造对象。感谢更新。考虑到指针算法没有在数组之外定义,这里是否明确允许
std::uninitialized\u default\u construct\n
工作?我想我还需要确保数组中所有后续对象的对齐,而不仅仅是第一个对象(公平地说,我的问题完全忽略了这一点!)我相信这在技术上确实是错误的,因为
std::aligned_alloc
是一个C库函数,不创建数组对象。因此,通过…@MichaelKenzel对结果执行指针算术(确实如此),那么为什么要
std::aligned_alloc
创建一个数组对象呢?它分配存储,您在该存储中构造对象。但是,我不确定
存储
是否可以在没有
std::laund的情况下用于访问这些对象