yohhoyの日記

技術的メモをしていきたい日記

単一メンバunionの使い道

プログラミング言語C++において、単一メンバしか含まない共用体(union)を用いるとオブジェクトの明示的な生成/破棄操作が可能となる。貧者(poor man's)のOptional。

#include <iostream>

template <typename T>
union Wrapper {
  // 共用体Uのコンストラクタ/デストラクタ定義は必須
  Wrapper() {}
  ~Wrapper() {}
  // 明示的なオブジェクト初期化
  void init() { new (&obj_) Holder; }
  // 明示的なオブジェクト廃棄
  void destroy() { obj_.~Holder(); }
  // 制御対象クラス
  struct Holder {
    T m_;
  } obj_;
};

struct S {
  S() { std::cout << "S::ctor\n"; }
  ~S() { std::cout << "S::dtor\n"; }
};

int main()
{
  Wrapper<S> opt;
  // このタイミングではS型オブジェクトは生成されない

  std::cout << "call init\n";
  opt.init();  // S::S()を呼び出し

  std::cout << "call destroy\n";
  opt.destroy();  // S::~S()を呼び出し
}

C++17 12.3/p1, 6より一部引用。

1 In a union, a non-static data member is active if its name refers to an object whose lifetime has begun and has not ended (6.8). At most one of the non-static data members of an object of union type can be active at any time, that is, the value of at most one of the non-static data members can be stored in a union at any time. (snip)

6 [Note: In general, one must use explicit destructor calls and placement new-expression to change the active member of a union. -- end note] [Example: Consider an object u of a union type U having non-static data members m of type M and n of type N. If M has a non-trivial destructor and N has a non-trivial constructor (for instance, if they declare or inherit virtual functions), the active member of u can be safely switched from m to n using the destructor and placement new-expression as follows:

u.m.~M();
new (&u.n) N;

-- end example]

関連URL