最終更新日時(UTC):
が更新

履歴 編集

アライメント指定されたデータの動的メモリ確保(C++17)

概要

クラスのアライメント要求がデフォルトで満たされるものより大きい場合でも、動的に確保されたメモリ領域が指定したアライメントを満たしていることが保証される。

特殊な命令を使う、メモリアクセスを最適化するなどの理由により、変数のアライメントが必要になることがある。そのような目的のため、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が存在する場合、互換性のため呼び出しはそちらで解決される。もしユーザー定義newalign_val_tを取るものと取らないものがある場合、取るものが優先される。deleteも同様である。

new Tの呼び出しがalign_val_tを取るnewで解決される場合、align_val_tの値はalignof(T)の結果になる。

関連項目

参照