关于C++内存对齐

时间:2023-03-09 21:01:45
关于C++内存对齐

关于C++内存对齐


C++11从标准层面引入了一些和内存对齐相关的特性,标准库也增加了对应的组件,这里稍微总结一下。

取得某个类型的对齐值

C++中的Object(对象)是指一块满足以下条件的内存区域:

  1. 具有size属性,即能用sizeof取其大小。
  2. 具有alignment属性,即能用alignof取其对齐量。这个在稍后有详细的阐述。
  3. 类型
  4. ……(lifetime等)

现在已经知道了每个对象都有其类型,这样的类型称为“对象类型”(object type)。每个对象类型都有一个alignment值,该值的类型为std::size_t,且总为2的整数次幂。我们可以通过关键字alignof或标准库中的std::alignment_of(声明位于头文件<type_traits>)获知此值,比如:

struct S { char a; double b }
int main(void)
{
cout << alignof(S) << endl;
cout << alignment_of<int>::value << endl;
}

C++17引入了std::alignment_of_v,允许这样的写法:

int main(void)
{
cout << alignment_of_v<double> << endl;
}

当然,只是语法糖而已。

指定类型的对齐规则

C++11引入了关键字alignas用于修饰类型,它有以下三种使用形式:

  1. alignas(expr),这里expr必须是一个编译期常量表达式,且应为2的整数次幂。
  2. alignas(Type),这个写法等价于alignas(alignof(Type))
  3. alignas(pack...),这里pack是个模板参数包,相当于对参数包中的每个元素P,同时以alignas(P)来修饰后面的类型。

下面看例子:

struct alignas(16) MyStruct
{
char ch;
}; int main(void)
{
MyStruct instanceOfMyStruct; //instanceOfMyStruct按16字节对齐
alignas(127 + 1) char charArray[128]; //charArray按128字节对齐
alignas(int) char ch; //ch按alignof(int)字节对齐
//...
}

堆上对象的内存对齐

我们已经能够指定某个类型的对齐规则了,但对于堆上申请下来的对象还缺乏控制。我们当然可以基于malloc自己写一个,不过已经有下面的几种方案:

  1. operator new允许通过一个std::align_val_t类型的参数来显示给出对齐要求,然而这是C++17才引入的,暂时没法广泛使用。
  2. 二段式构造。先调用_aligned_malloc(Windows)或者posix_memalign(Posix)拿到一块内存,然后用placement new构造对象。

其他

C++11引入的std::aligned_storage(头文件<type_traits>中)用于获得一块按指定规则对齐的内存块。它相当于:

template<std::size_t Len, std::size_t Align>
struct aligned_storage
{
struct type
{
alignas(Align) unsigned char data[Len];
};
};

C++11引入的std::max_align_t:“std::max_align_t is a trivial type whose alignment requirement is at least as strict (as large) as that of every scalar type”,也就是任何一个scalar type的默认对齐大小都不会超过alignof(max_align_t)