alignas说明符是否与'new'一起使用?

Ske*_*een 11 c++ memory-alignment new-operator c++11

我的问题很简单;

alignas说明符是否与'new'一起使用?也就是说,如果一个struct定义为对齐,那么在分配new时它是否会对齐?

Nic*_*las 12

如果您的类型的对齐没有过度对齐,那么是,默认new将起作用."过度对齐"表示您指定的对齐alignas大于alignof(std::max_align_t).默认情况下new,或多或少会偶然使用非过度对齐的类型; 默认内存分配器将始终分配对齐等于的内存alignof(std::max_align_t).

如果您的类型的对齐过度对齐,那么您的运气不好.您编写的默认操作符new或任何全局new操作符都不能知道该类型所需的对齐方式,更不用说分配适合它的内存.帮助这种情况的唯一方法是重载类operator new,它将能够查询类的对齐方式alignof.

当然,如果该类用作另一个类的成员,这将没有用.除非其他类也超载operator new.所以简单的事情new pair<over_aligned, int>()就行不通了.

一种用于C++ 17提案(已接受)增加了用于在对准类型的动态分配支持,通过具有的重载operator new/delete该取alignof的类型的被分配.这也将支持小于最大对齐类型的对齐,因此您的内存分配器无需始终返回与之对齐的内存alignof(std::max_align_t).

话虽这么说,编译器根本不需要支持过度对齐的类型.

  • 要添加:可以通过`alignof(std :: max_align_t)`查询这个最大对齐.对齐大于此的类型称为*over-aligned*,它们的支持是有条件的,实现定义的. (4认同)

小智 12

不,不是的.结构将填充到请求的对齐方式,但不会对齐.但是,有可能在C++ 17中允许这样做(事实上​​,这个C++ 17提议应该很好地证明这在C++ 11中不起作用).

我已经看到这似乎适用于一些内存分配器,但那是纯粹的运气.例如,一些内存分配器会将它们的内存分配与请求大小的2的幂(最多4KB)对齐,作为分配器的优化(减少内存碎片,可能更容易重用以前释放的内存等等) .但是,我测试的OS X 10.7和CentOS 6系统中包含的new/malloc实现不会这样做,并且使用以下代码失败:

#include <stdlib.h>
#include <assert.h>

struct alignas(8)   test_struct_8   { char data; };
struct alignas(16)  test_struct_16  { char data; };
struct alignas(32)  test_struct_32  { char data; };
struct alignas(64)  test_struct_64  { char data; };
struct alignas(128) test_struct_128 { char data; };
struct alignas(256) test_struct_256 { char data; };
struct alignas(512) test_struct_512 { char data; };

int main() {
   test_struct_8   *heap_8   = new test_struct_8;
   test_struct_16  *heap_16  = new test_struct_16;
   test_struct_32  *heap_32  = new test_struct_32;
   test_struct_64  *heap_64  = new test_struct_64;
   test_struct_128 *heap_128 = new test_struct_128;
   test_struct_256 *heap_256 = new test_struct_256;
   test_struct_512 *heap_512 = new test_struct_512;

#define IS_ALIGNED(addr,size)   ((((size_t)(addr)) % (size)) == 0)

   assert(IS_ALIGNED(heap_8, 8));
   assert(IS_ALIGNED(heap_16, 16));
   assert(IS_ALIGNED(heap_32, 32));
   assert(IS_ALIGNED(heap_64, 64));
   assert(IS_ALIGNED(heap_128, 128));
   assert(IS_ALIGNED(heap_256, 256));
   assert(IS_ALIGNED(heap_512, 512));

   delete heap_8;
   delete heap_16;
   delete heap_32;
   delete heap_64;
   delete heap_128;
   delete heap_256;
   delete heap_512;

return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 这是正确的,最上面的答案不是。C++11 *将*为您提供堆栈分配对象的正确对齐方式,但默认内存分配器不会为您提供正确的对齐方式。所以现在,您必须使用操作系统检测宏中包含的 POSIX/windows 函数。例如; Linux/OSX/BSD 上的 posix_memalign 和 Windows 上的aligned_alloc。对于使用英特尔 MKL 的人来说,有 mkl_malloc 和 mkl_free。 (3认同)