Rokiのチラ裏

学生による学習のログ

ビルトインを使わずに任意の型のアラインメントを計算

alignment_of は C++11 で標準化されており、殆どの場合はビルトイン関数を呼び出す実装となっているが、ふと Boost の実装を見るとなるほど〜という感じだったのでメモ。Boost による実装は今からかな〜り前からあるので、今更感はあるが。

// 以下の実装は、より簡略化/多少の改変が施されている事に留意されたし

template <class T>
struct alignment_hack {
    char c;
    T t;
    alignment_hack() = delete;
};

template <unsigned A, unsigned S>
struct alignment_logic 
    : public integral_constant<std::size_t, A < S ? A : S> {};

template <class T>
struct alignment_of
    : public integral_constant<std::size_t, alignment_logic<sizeof(alignment_of_hack<T>) - sizeof(T), sizeof(T)>::value> {};

alignment_hack で、任意のタイプT*1の前に、1 バイトを置いているのが肝である。実際に型を入れてメモリ空間を想像すると分かりやすい*2。例えば、T が int32_t/uint32_t である場合、alignment requirement*3 に則って alignment_hack::t の後方に 3 バイトのパディングを入れ alignment_hack が 8 バイトとなるため、そこから差し引いてアライメントの値である 4 を得られる。次に、struct X{ char a[5]; } を当てはめたとしよう。この場合、パディングは挿入されないのでそのままsizeof(X)の値を引いてアライメントの値 1 を取得する事ができる。

この実装は必ずしもアライメントの実数値を確実に取得できるものではないという事に留意しなければならない。保証されているのは、アライメントの値の倍数である太字で強調したのは、パディングがどの部分に取られるか規定されているわけではないためである。また、vptr などがどこに挿入されるかなども推測できるものではない。殆どの実装では大抵メンバの後ろに挿入されるため、よくあるケースではないが、実際に起きたケースも報告されている

このトリックを利用した自作ライブラリの方の実装は以下の通りである。

*1:簡略化のためこの例では全ての型が意図した通りに動かない。例えば、参照型、 void、long double などは、特殊化が必要となる。

*2:論理的な観点からの説明は以前書いた文書を参照。

*3:6.7.1 Fundamental types/1