残念ながら、最大位置合わせを確実にすることは、本来あるべきよりもはるかに困難であり、AFAIKの保証された解決策はありません。GotWブログ(Fast Pimplの記事)から:
union max_align {
short dummy0;
long dummy1;
double dummy2;
long double dummy3;
void* dummy4;
/*...and pointers to functions, pointers to
member functions, pointers to member data,
pointers to classes, eye of newt, ...*/
};
union {
max_align m;
char x_[sizeofx];
};
これは完全に移植可能であることが保証されているわけではありませんが、これが期待どおりに機能しないシステムがほとんどないかまったくないため、実際には十分に近いです。
それは私がこれについて知っている最も近い「ハック」についてです。
超高速割り当てのために私が個人的に使用した別のアプローチがあります。それは悪いことですが、私は速度が品質の最大の尺度の1つであるレイトレーシング分野で働いており、コードを毎日プロファイリングしています。これには、ローカルスタックのように機能する事前に割り当てられたメモリを備えたヒープアロケータの使用が含まれます(割り当て時にポインタをインクリメントし、割り当て解除時に1つデクリメントします)。
特にニキビに使っています。ただし、アロケータを持っているだけでは十分ではありません。このようなアロケータが機能するには、クラスFooのメモリがコンストラクタで割り当てられ、同じメモリがデストラクタでのみ割り当て解除され、Foo自体がスタック上に作成されると想定する必要があります。安全を確保するために、クラスの「this」ポインタがローカルスタック上にあるかどうかを確認して、超高速ヒープベースのスタックアロケータを使用できるかどうかを判断する関数が必要でした。そのためには、OS固有のソリューションを調査する必要がありました。Win32 / Win64用のTIBとTEBを使用し、同僚がLinuxとMacOSX用のソリューションを見つけました。
その結果、スタック範囲、アライメント要件を検出するためのOS固有の方法を調査し、多くのテストとプロファイリングを行った後、約ではなく、ティックカウンターベンチマークに従って4クロックサイクルでメモリを割り当てることができるアロケータができました。新しいmalloc/operatorの場合は400サイクル(テストにはスレッドの競合が含まれていたため、mallocはシングルスレッドの場合よりも少し速くなる可能性があります(おそらく数百サイクル))。スレッドごとのヒープスタックを追加し、使用されているスレッドを検出して、時間を約12サイクルに増やしましたが、クライアントはスレッドアロケータを追跡して4サイクルの割り当てを取得できます。マップからメモリ割り当てベースのホットスポットを一掃しました。
このような問題をすべて解決する必要はありませんが、高速アロケータを作成する方が、max_align
ここにあるようなものよりも簡単で一般的に適用できる場合があります(例:実行時に割り当て/割り当て解除するメモリの量を決定できるようにする)。max_align
使い方は簡単ですが、メモリ割り当ての速度を求めている場合(そして、コードのプロファイルを作成し、malloc / free / operator new / deleteにホットスポットがあり、主要な貢献者が自分で制御できるコードにあると仮定した場合)、独自のアロケータを作成することで、実際に違いを生むことができます。