【发布时间】:2013-03-08 20:39:04
【问题描述】:
我的问题很简单;
alignas 说明符是否与“new”一起使用?即如果一个struct被定义为对齐,分配new时是否会对齐?
【问题讨论】:
标签: c++ c++11 new-operator memory-alignment
我的问题很简单;
alignas 说明符是否与“new”一起使用?即如果一个struct被定义为对齐,分配new时是否会对齐?
【问题讨论】:
标签: c++ c++11 new-operator memory-alignment
在 C++17 之前,如果您的类型的对齐方式没有过度对齐,那么可以,默认的 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 adds a number of memory allocators 给定了正在使用的类型的对齐方式。这些分配器专门用于过度对齐的类型(或者更具体地说,new-extended over-aligned types)。所以new pair<over_aligned, int>() 将在 C++17 中工作。
当然,这只适用于分配器处理过度对齐的类型。
【讨论】:
alignof(std::max_align_t)查询这个最大对齐。对齐大于此的类型称为过度对齐,它们的支持是有条件的、实现定义的。
void* operator new(std::size_t count) 无法直接获取用户指定的对齐方式。除非您将对齐编码到计数中,否则这是非常错误的。或者您可以编写一个自定义的placement-new 运算符,它接受一个额外的size_t 进行对齐。
不,它没有。该结构将被填充到请求的对齐位置,但不会对齐。但是,有可能是 allowed in 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;
}
【讨论】: