[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來在我想要的地方構建對象。 我知道我使用的一種情況是幫助創建一個異構循環緩衝區

這當然不是因為內心的淡淡,但這就是為什麼他們會為它的語法有點粗糙。




請參閱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;



頭怪:賓果! 你完全了解 - 這正是它的理想之處。 在許多嵌入式環境中,外部約束和/或總體使用場景迫使程序員將對象的分配與其初始化分開。 總之,C ++稱之為“實例化”; 但是無論何時必須顯式調用構造函數的動作而沒有動態或自動分配,放置新元素都是實現它的方法。 它也是定位固定在硬件組件(內存映射I / O)地址上的全局C ++對像或任何靜態對象(無論出於何種原因必須位於固定地址)的完美方式。




它被std::vector<>因為std::vector<>通常會分配比vector<>中的objects更多的內存。




我用它根據包含從網絡接收到的消息的內存創建對象。




當你想重新初始化全局或靜態分配的結構時,它也很有用。

舊的C方法是使用memset()將所有元素設置為0.由於vtable和自定義對象構造函數,您無法在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.
 }



一般來說,放置新用於擺脫“正常新”的分配成本。

我使用它的另一個場景是我想要訪問指向仍然要構造的對象的指針 ,以實現每個文檔的單例。




如果你正在構建一個內核,那麼它很有用 - 你在哪裡放置你從磁盤或頁表中讀取的內核代碼? 你需要知道去哪裡跳。

或者在其他非常罕見的情況下,比如當你有大量的分配空間,並且想要將一些結構放置在對方後面時。 它們可以用這種方式打包,而不需要offsetof()運算符。 儘管如此,還有其他一些技巧。

我也相信一些STL實現使用了新的位置,比如std :: vector。 他們以這種方式為2 ^ n個元素分配空間,並且不需要總是重新分配。




我已經運行過的一個地方是在分配連續緩衝區的容器中,然後根據需要填充對象。 如前所述,std :: vector可能會這樣做,並且我知道某些版本的MFC CArray和/或CList會這樣做(因為這是我第一次碰到它的地方)。 緩衝區過度分配方法是一種非常有用的優化方式,並且放置新增功能幾乎是構建該場景中對象的唯一方法。 它也有時用於在直接代碼之外分配的內存塊中構造對象。

我曾經以類似的身份使用它,儘管它並不經常出現。 不過,這是C ++工具箱的一個有用工具。






Related