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;
}

也可以使用 Ont/<代码>操作符来获得给定类型的对齐要求。首先,判断是否询问C或C++,虽然<>代码> AlalOcth< /C>不是它们中的任一个。<代码> AlOLCA< /COD> 16位上的对齐分配。如果您需要另一个校准-分配更多内存并自行校准将
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;
}