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

履歴 編集

class template
<type_traits>

std::aligned_union(C++11)(C++23で非推奨)

namespace std {
  template <std::size_t Len,
            class... Types>
  struct aligned_union {
    using type = ;
    static constexpr std::size_t alignment_value = ;
  };                                                                  // (1) C++11

  template <std::size_t Len, class... Types>
  using aligned_union_t = typename aligned_union<Len,Types...>::type; // (2) C++14
}

この機能はC++23で非推奨となった。代わりにalignas(Ts...) std::byte[std::max({sizeof(Ts)...})];を使用することを推奨する。

概要

アライメント調整された共用体領域を作る。

要件

Types...に、1個以上の型が与えられること。かつ、それらの型は全て完全型であること。

効果

  • aligned_unionは、領域サイズLen、要素型列Types...で調整した未初期化の共用体領域をメンバ型typeとして定義する。
  • メンバ型typeは、以下の型分類となる:
    • C++11 : Types...のいずれかの型が非POD型だとしても、メンバ型typePOD型となる
    • C++20 : Types...のいずれかの型が非トリビアル型だとしても、メンバ型typeトリビアル型となる

また、Types...全ての厳格なアライメント値を、std::size_t型の静的メンバ定数alignment_valueとして定義する。

非推奨の詳細 (C++23)

この機能は、いくつかの点で高いレベルの有害になりえる:

  • この機能を呼び出すことで未定義動作を引き起こす (この型はストレージを提供するわけではない)
  • 保証が正しくない (標準では、型が少なくとも要求された以上の大きさであることのみを要件としているだけで、上限サイズを要求できない)
  • APIが多くの理由で間違っている。そのためにこのAPIを使うために繰り返し同じ事前作業が必要になる。API設計が間違っている理由は以下:
    • ::typeの値にアクセスするためにreinterpret_castが必要となってしまう。これによってconstexprで使用できず、未定義動作を引き起こせてしまう
    • C++14で導入されたaligned_union_tではなく誤ってaligned_unionを使用してしまい、その違いに気づきにくい (aligned_union::typeを指定しなければならない)
    • 少なくともNバイト以上という指定はできるが、実際のサイズ (上限サイズ) を指定できないため、必要以上のメモリが使用される可能性がある

これらの問題はaligned_storageも同様である。aligned_union固有の問題はそれほどひどくないが、それでも望ましくない以下のような問題がある:

  • 第1テンプレートパラメータが無意味
    • この機能は、可変個のすべての型のサイズとアライメントを推論し、それらの最大値を実際のストレージとして使用する。先頭のテンプレートパラメータはストレージの最小サイズである。すべての型がそれより小さい場合でも、ストレージは第1テンプレートパラメータより小さくならない
    • 最小サイズを必要とすることはめずらしいことであり、ほとんどの場合はaligned_union_t<0、Ts...>のように使用する。この引数0は機能に精通していなければ理解しにくい
  • サイズとアライメントの推論がaligned_storageと一貫していない
    • 一貫した仕様であるならば、aligned_union_t<0、T>のような型をひとつだけ指定する用途につながるが、現在の仕様は何を意図していたのか不明である

この機能を以下のように置き換えることを推奨する:

template <typename... Ts>
class MyContainer {
  // [...]
private:
- std::aligned_union_t<0, Ts...> t_buff;
+ alignas(Ts...) std::byte t_buff[std::max({sizeof(Ts)...})];
  // [...]
};

#include <iostream>
#include <string>
#include <type_traits>

union X {
  int n;
  std::string s;

  X(const char* str)
    : s(str) {}
};

int main()
{
  using aligned_X = std::aligned_union<sizeof(X), int, std::string>;

  aligned_X::type x;

  new (&x) X("hello");

  std::cout << reinterpret_cast<X&>(x).s << std::endl;
  std::cout << aligned_X::alignment_value << std::endl;
}

出力例(アライメント値は処理系定義)

hello
8

バージョン

言語

  • C++11

処理系

  • Clang: 3.3
  • GCC: 5.0
  • Visual C++: 2008 (std::tr1), 2010, 2012, 2013, 2015
    • 2012は、alignment_valueが定義されていない。
    • 2012は、可変引数テンプレートに対応していないため、不完全な実装である。
    • aligned_union_tは2013から

関連項目

参照