C++ 在堆栈上像alloca一样分配对齐的内存
C++ 在堆栈上像alloca一样分配对齐的内存,c++,memory-management,c++17,c11,alloca,C++,Memory Management,C++17,C11,Alloca,\u alloca()的文档说明: _alloca例程返回一个指向分配空间的空指针, 保证适当对齐以存储任何类型的 反对 然而,它说: _alloca需要16字节对齐,另外还需要使用帧指针 因此,在第一次引用中,他们似乎忘记了32字节对齐的AVX/AVX2类型,如\uuuuM256d 另一件让我困惑的事情是,第一页说\u alloca()已被弃用,但它建议使用一个函数,可以从堆而不是堆栈分配内存(这在我的多线程应用程序中是不可接受的) 那么,有人能告诉我,是否有一些现代的(也许是新的C/C++标
\u alloca()
的文档说明:
_alloca例程返回一个指向分配空间的空指针,
保证适当对齐以存储任何类型的
反对
然而,它说:
_alloca需要16字节对齐,另外还需要使用帧指针
因此,在第一次引用中,他们似乎忘记了32字节对齐的AVX/AVX2类型,如\uuuuM256d
另一件让我困惑的事情是,第一页说\u alloca()
已被弃用,但它建议使用一个函数,可以从堆而不是堆栈分配内存(这在我的多线程应用程序中是不可接受的)
那么,有人能告诉我,是否有一些现代的(也许是新的C/C++标准?)方法用于对齐堆栈内存分配
澄清1:请不要提供要求数组大小为编译时常量的解决方案。My函数根据运行时参数值分配可变数量的数组项。C++11引入了
alignof
运算符:
alignof表达式产生其操作数类型的对齐要求
您可以按如下方式使用它:
struct s {};
typedef s __attribute__ ((aligned (64))) aligned_s;
std::cout << alignof(aligned_s); // Outputs: 64
支持VLA的编译器也将允许新定义类型的编译器。使用_alloca()过度分配,然后手动对齐。像这样:
const int align = 32;
void *p =_alloca(n + align - 1);
__m256d *pm = (__m256d *)((((int_ptr_t)p + align - 1) / align) * align);
如有必要,用#define
替换const
。现代方法是:
在您的问题的上下文中—希望在堆上分配,但不要这样做—我假设您分配的内存可能不止是一些小的编译时常量内存。在这种情况下,您只需使用alloca()
调用来粉碎堆栈。相反,请使用线程安全内存分配器。我确信GitHub上有用于此的库(最坏的情况下,您可以使用全局互斥来保护分配调用,尽管如果您需要大量的互斥,这会很慢)
另一方面,如果您事先知道分配大小的上限,只需在线程本地存储中预先分配那么多内存;或者使用固定大小的本地数组(将在堆栈上分配)。\u alloca()
肯定不是处理堆栈上对齐的标准或便携式方法。幸运的是,在C++11中,我们得到了alignas
和std::aligned\u存储
。这两种方法都不会强迫您在堆上放置任何东西,因此它们应该适用于您的用例。例如,要将结构数组与32字节边界对齐,请执行以下操作:
#include <type_traits>
struct bar { int member; /*...*/ };
void fun() {
std::aligned_storage<sizeof(bar), 32>::type array[16];
auto bar_array = reinterpret_cast<bar*>(array);
}
void bun() {
alignas(32) bar b;
}
也可以使用
std::aligned_存储
满足您的需要吗?您可以将对齐方式指定为第二个模板参数,它来自使用alignas
的示例实现的堆栈。什么是alignof(_m256d),为了那些没有平台扩展的人的利益?@KerrekSB,问题是:32字节。这种方法允许非常量数组大小吗?数组大小在运行时的函数调用之间发生变化,我需要\u alloca()
。cl不支持非常量数组size@SergeRogatch,动态数组(又称VLA),但没有成功。不过,G++(4.6.3)和Clang(900.0.38)允许这样做。更好的(uu m256d*)((UINT_PTR)p+(align-1))&~(align-1))
都可以:)问题是,过度分配到最坏的情况下(align-1)额外字节。然后进行取整。实际上,您只需要超额分配16个字节,然后选中p%32!=0
。如果不是0,则添加16并完成。地址需要按规范对齐16个字节。规范真的这么说吗?我认为这是一个GCC实现的怪癖。举个例子?不要在堆栈上进行可变长度分配-这就是为什么?实际上可变长度分配在相对较小的块上非常有效。如果我们在用户模式和自己的exe文件中执行此操作(因此我们确切地知道堆栈大小,并可以在构建时进行设置)。通常我们在堆栈中自由分配数十万字节。另一个问题是,当我们第一次这样做并分配几个页面(4KB)或更多页面时,这将缓慢地比较堆分配(如果之前没有将保护页向下移动)。如果定义了堆栈溢出行为。(所有这些都适用于windows)
void bun() {
alignas(32) bar b;
}