未初期化な領域とアラインメント

http://d.hatena.ne.jp/Cryolite/20051102#p1
を書いておいて,未初期化な領域とアラインメントについての配慮が実際に必要になる具体例を書かないと片手落ちな気がするのでとりあえず自分が知っている範囲で列挙しておきます.

  • 自動変数として確保した領域を malloc や new で確保した領域の(効率的な)代替として用いる場合
  • operator new の置き換え(グローバル・クラススコープ両方)

グローバルの operator new は任意の型に対して安全なアラインメントのメモリを返さなければならないことを規格が(そして operator new に依存する他の言語規格・ライブラリ全てが)要求しています.
また,クラススコープの operator new の置き換えについてもそのクラスのアラインメント要求を満たすメモリ領域を返さなければなりません.

  • その他,独自のメモリ管理機構

例えば,Boost.Pool においては http://www.boost.org/libs/pool/doc/implementation/alignment.html にあるようにアラインメントについて注意深く配慮しています.自身で独自にメモリ管理機構を実装する場合はこのような配慮が必須となります.

  • 複数の型を単一のメモリ領域に配置するような実装のクラス

Boost.Any, Boost.Covariant, Boost.Optional のようなクラスで,異なる型が単一のメモリ領域に排他的に構築されるような実装のクラス

  • 汎用ノードタイプコンテナ(リストなど)で番兵(セントリー)を用いた実装を行う場合

汎用リストクラスを,番兵(末尾に常に存在する余計なノード)を用いて実装する場合を考えてみます.リストのノードクラスには実際にノードに保持されるメンバと前後のノードへのポインタを持ちますが,これらのデータメンバはどのように宣言するべきでしょうか?

template<class T>
class List{
  class Node{
    ..... /* 問題:データメンバの宣言はどうするべきか? */
  };
};
  • 後,MMX とか SSE とかありますけれど C++ 標準の範囲を超えるので割愛

ちょっとだけ言及しておくと,boost::type_with_alignment は C++ 標準の範囲を超えるアラインメントには対応していません.例えば VC++ で 32-bit 環境だと,boost::type_with_alignment が対応している最大アラインメントは 8 です.これより大きいアラインメントを boost::type_with_alignment の枠組みでやるには,コンパイラ固有の手法で boost::type_with_alignment を特殊化します.例えば,VC++ では __declspec(align(#)) を使って

__declspec(align(16)) struct a16{};
__declspec(align(32)) struct a32{};
__declspec(align(64)) struct a64{};

namespace boost{

template<>
class type_with_alignment<16>
{
  typedef a16 type;
};

template<>
class type_with_alignment<32>
{
  typedef a32 type;
};

template<>
class type_with_alignment<64>
{
  typedef a64 type;
};

}

こんな感じでやれば,boost::type_with_alignment を16バイトアラインメントや32バイトアラインメントに対応させることができます.
GCC の場合は,__attribute__((__aligned__(#))) を使って同様のことができますが,GCC の場合はすでにライブラリ側で32バイトアラインメントまで特殊化されています.