[C++] 「プレースメント新規」にはどのような用途がありますか?



Answers

カスタムメモリプールで使用します。 ちょうどスケッチ:

class Pool {
public:
    Pool() { /* implementation details irrelevant */ };
    virtual ~Pool() { /* ditto */ };

    virtual void *allocate(size_t);
    virtual void deallocate(void *);

    static Pool::misc_pool() { return misc_pool_p; /* global MiscPool for general use */ }
};

class ClusterPool : public Pool { /* ... */ };
class FastPool : public Pool { /* ... */ };
class MapPool : public Pool { /* ... */ };
class MiscPool : public Pool { /* ... */ };

// elsewhere...

void *pnew_new(size_t size)
{
   return Pool::misc_pool()->allocate(size);
}

void *pnew_new(size_t size, Pool *pool_p)
{
   if (!pool_p) {
      return Pool::misc_pool()->allocate(size);
   }
   else {
      return pool_p->allocate(size);
   }
}

void pnew_delete(void *p)
{
   Pool *hp = Pool::find_pool(p);
   // note: if p == 0, then Pool::find_pool(p) will return 0.
   if (hp) {
      hp->deallocate(p);
   }
}

// elsewhere...

class Obj {
public:
   // misc ctors, dtors, etc.

   // just a sampling of new/del operators
   void *operator new(size_t s)             { return pnew_new(s); }
   void *operator new(size_t s, Pool *hp)   { return pnew_new(s, hp); }
   void operator delete(void *dp)           { pnew_delete(dp); }
   void operator delete(void *dp, Pool*)    { pnew_delete(dp); }

   void *operator new[](size_t s)           { return pnew_new(s); }
   void *operator new[](size_t s, Pool* hp) { return pnew_new(s, hp); }
   void operator delete[](void *dp)         { pnew_delete(dp); }
   void operator delete[](void *dp, Pool*)  { pnew_delete(dp); }
};

// elsewhere...

ClusterPool *cp = new ClusterPool(arg1, arg2, ...);

Obj *new_obj = new (cp) Obj(arg_a, arg_b, ...);

今度は、単一のメモリ領域内でオブジェクトをクラスタリングし、非常に速いが割り当て解除を行わないアロケータを選択し、メモリマッピングを使用し、プールを選択してオブジェクトの配置に引数として渡すことで、新しい演算子。

Question

ここで誰かがC ++の "placement new"を使ったことはありますか? もしそうなら、何のために? メモリマップされたハードウェア上でのみ役に立つと思う。




私はそれをリアルタイムプログラミングに使用しました。 どのくらいの時間がかかるか保証されていないため、通常システムの起動後に動的割り当て(または割り当て解除)を実行する必要はありません。

私ができることは、(クラスが必要とするものであればどんな量でも保持するのに十分な大きさの)大きなメモリを事前に割り当てることです。 その後、私は物事を構築する方法を実行時に把握したら、配置newを使用して、必要なところでオブジェクトを構築することができます。 私がそれを使用したことを知っている1つの状況は、異種循環バッファを作成することでした。

それは確かに心の弱い人のためではありませんが、それはそれがちょっとぎこちなく文法を作っている理由です。




カーネルを構築する場合に便利です。ディスクやページテーブルから読み込んだカーネルコードはどこに置いていますか? ジャンプする場所を知る必要があります。

または、割り当てられた部屋の負荷があり、互いに背後にいくつかの構造を配置する場合など、非常にまれな状況です。 これらはoffsetof()演算子を必要とせずにこのようにパックできます。 しかし、それのための他のトリックもあります。

また、いくつかのSTL実装では、std :: vectorのような新しい配置を使用すると考えています。 そのように2 ^ n要素のための部屋を割り当て、いつもreallocする必要はありません。




頭のオタク:ビンゴ! あなたはそれを完全に得ました - それはまさにそれが完璧なものです。 多くの組み込み環境では、外部制約および/または全体的な使用シナリオにより、プログラマーはオブジェクトの割り振りを初期化から切り離すことができます。 まとめると、C ++はこの「インスタンス化」を呼び出します。 動的または自動割り当てなしで明示的にコンストラクタのアクションを呼び出さなければならない場合は、常に新しい配置がそれを行う方法です。 また、ハードウェアコンポーネント(メモリマップされたI / O)のアドレスに固定されたグローバルC ++オブジェクト、または何らかの理由で固定アドレスに存在する必要がある静的オブジェクトを見つけるのに最適な方法です。




私は、ネットワークから受信したメッセージを含むメモリに基づいてオブジェクトを作成するために使用しました。




私はそれを渡って実行した1つの場所は、連続したバッファを割り当て、必要に応じてそれをオブジェクトで埋めるコンテナ内にあります。 前述したように、std :: vectorはこれを行うかもしれませんが、MFCのいくつかのバージョンを知っています.Crrrayおよび/またはCListはこれを行いました。 バッファオーバーアロケーションメソッドは非常に便利な最適化であり、プレースメントnewはそのシナリオでオブジェクトを構築する唯一の方法です。 ダイレクトコードの外側に割り当てられたメモリブロックにオブジェクトを構築するために使用されることもあります。

私は同様の能力でそれを使用しましたが、それは頻繁に起きません。 しかし、C ++ツールボックスにとっては便利なツールです。




これはstd::vector<>によって使用されstd::vector<>これは、 std::vector<>は通常、 vector<> objectsより多くのメモリを割り当てます。




グローバルまたは静的に割り当てられた構造体を再初期化する場合にも便利です。

古いCの方法では、 memset()を使ってすべての要素を0に設定していました.vtablesやカスタムオブジェクトのコンストラクタのためにC ++で行うことはできません。

だから私は時々以下の

 static Mystruct m;

 for(...)  {
     // re-initialize the structure. Note the use of placement new
     // and the extra parenthesis after Mystruct to force initialization.
     new (&m) Mystruct();

     // do-some work that modifies m's content.
 }



一般的に、配置newは、「通常の新規」の割り当てコストを取り除くために使用されます。

私が使った別のシナリオは、ドキュメント単位のシングルトンを実装するために、まだ構築されていたオブジェクトへのポインタにアクセスしたいという場です。




http://xll.codeplex.comのxllプロジェクトのfp.hファイルを参照してください。それは、それらの次元を持ち歩くのが好きな配列の "コンパイラの不当な不安定さ"の問題を解決します。

typedef struct _FP
{
    unsigned short int rows;
    unsigned short int columns;
    double array[1];        /* Actually, array[rows][columns] */
} FP;





Links