最近、アラインメントの制約に違反しているのではないかと心配しているコードベースを見ました。以下に示す最小限の例を作成するために、それをスクラブしました。簡単に言えば、プレーヤーは次のとおりです。
プール。これは、「効率的」の定義のために、メモリを効率的に割り当てるクラスです。プールは、要求されたサイズに合わせて調整されたメモリのチャンクを返すことが保証されています。
オブジェクトリスト。このクラスは、同種のオブジェクトのコレクションを格納します。オブジェクトの数が特定のしきい値を超えると、内部表現がリストからツリーに変更されます。Obj_listのサイズは 1 つのポインターです (64 ビット プラットフォームでは 8 バイト)。もちろん、人口の多い店舗はそれを上回ります。
集計します。このクラスは、システムで非常に一般的なオブジェクトを表します。その歴史は初期の 32 ビット ワークステーション時代にまでさかのぼり、その結果、できるだけ少ないスペースを使用するように (同じ 32 ビット時代に) 「最適化」されました。Aggregateは空にすることも、任意の数のオブジェクトを管理することもできます。
この例では、Aggregateアイテムは常にPoolから割り当てられるため、常に整列されます。この例でObj_listが出現するのはAggregateオブジェクトの「非表示」メンバーのみであるため、常に配置 newを使用して割り当てられます。サポート クラスは次のとおりです。
class Pool
{
public:
Pool();
virtual ~Pool();
void *allocate(size_t size);
static Pool *default_pool(); // returns a global pool
};
class Obj_list
{
public:
inline void *operator new(size_t s, void * p) { return p; }
Obj_list(const Args *args);
// when constructed, Obj_list will allocate representation_p, which
// can take up much more space.
~Obj_list();
private:
Obj_list_store *representation_p;
};
そして、ここに集計があります。メンバー宣言member_list_store_dに注意してください。
// Aggregate is derived from Lesser, which is twelve bytes in size
class Aggregate : public Lesser
{
public:
inline void *operator new(size_t s) {
return Pool::default_pool->allocate(s);
}
inline void *operator new(size_t s, Pool *h) {
return h->allocate(s);
}
public:
Aggregate(const Args *args = NULL);
virtual ~Aggregate() {};
inline const Obj_list *member_list_store_p() const;
protected:
char member_list_store_d[sizeof(Obj_list)];
};
私が最も関心を持っているのは、そのデータ メンバーです。初期化とアクセスの擬似コードは次のとおりです。
Aggregate::Aggregate(const Args *args)
{
if (args) {
new (static_cast<void *>(member_list_store_d)) Obj_list(args);
}
else {
zero_out(member_list_store_d);
}
}
inline const Obj_list *Aggregate::member_list_store_p() const
{
return initialized(member_list_store_d) ? (Obj_list *) &member_list_store_d : 0;
}
char 配列を、 NULL またはクラスのインスタンスに初期化されたObj_list型へのポインターに置き換えることを提案したくなるかもしれません。これにより適切なセマンティクスが得られますが、メモリ コストがシフトするだけです。メモリが依然として貴重な場合 (これは EDA データベース表現である可能性があります)、Aggregateオブジェクトにメンバーがある場合、char 配列をObj_listへのポインターに置き換えると、ポインターが 1 つ増えることになります。
それに加えて、ここでの主な問題であるアラインメントから気をそらされたくありません。上記の構成には問題があると思いますが、「システム/ライブラリ」 newのアライメント動作に関する漠然とした議論以上のものを標準で見つけることはできません。
では、上記の構造は時折パイプの失速を引き起こす以上のことをするのでしょうか?
編集:埋め込まれた char 配列を使用してアプローチを置き換える方法があることを認識しています。元の建築家もそうでした。メモリが貴重だったので、彼らはそれらを破棄しました。さて、そのコードに触れる理由があれば、おそらく変更するでしょう。
しかし、このアプローチに内在するアラインメントの問題についての私の質問は、人々が解決してくれることを願っています。ありがとう!