このページはC++17に採用された言語機能の変更を解説しています。
のちのC++規格でさらに変更される場合があるため関連項目を参照してください。
概要
クラスのアライメント要求がデフォルトで満たされるものより大きい場合でも、動的に確保されたメモリ領域が指定したアライメントを満たしていることが保証される。
特殊な命令を使う、メモリアクセスを最適化するなどの理由により、変数のアライメントが必要になることがある。そのような目的のため、C++11においてalignas
を用いてクラスのアライメントを指定できるようになった。しかし、デフォルトで満たされるアライメントよりも大きな値を設定した場合には、動的確保したメモリ領域がその指定に沿ってアライメントされる保証はなかった。
// 16バイト境界にアライメントされるべきクラス
class alignas(16) float4 {
float f[4];
};
float4 v; // C++11でも適切にアライメントされる
float4* p = new float4[1000]; // C++17以降では適切にアライメントされる
float* q = new (std::align_val_t{16}) float[4]; // new演算子に直接アライメント指定することもできる
C++17以前で適切にアライメントされたメモリ領域を動的に確保するためには、C++11で追加されたstd::align
を用いて大きく確保した領域から指定を満たす部分を取り出すか、posix_memalign
や_aligned_malloc
などの処理系固有の関数を使用する必要があった。
仕様
operator new
に、align_val_t
を取るオーバーロードが追加された。align_val_t
は意図しない型変換を防止するためのenum class
であり、列挙値は定義されない。
namespace std {
enum class align_val_t : std::size_t {};
}
void* operator new(std::size_t size, std::align_val_t alignment);
動的確保時になされるアライメントのデフォルト値は__STDCPP_DEFAULT_NEW_ALIGNMENT__
で定義されている。これを超えるアライメント要求を持つクラスに対するnew
呼び出しは、align_val_t
が渡された場合のもので解決される。また、対応するユーザー定義new
が存在する場合、互換性のため呼び出しはそちらで解決される。もしユーザー定義new
にalign_val_t
を取るものと取らないものがある場合、取るものが優先される。delete
も同様である。
new T
の呼び出しがalign_val_t
を取るnew
で解決される場合、align_val_t
の値はalignof(T)
の結果になる。