最終更新日時: 2025年07月10日 10時26分30秒 (JST)
Koichi Murase が更新

履歴 編集

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

このページは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)`の結果になる。

## 関連項目

- `<new>`
- `std::align`
- C++11 `alignas`
- C++11 `alignof`

## 参照

- P0035R4 Dynamic memory allocation for over-aligned data
- New `new()` - The C++17's Alignment Parameter for Operator `new()`