代码之家  ›  专栏  ›  技术社区  ›  Head Geek

“放置新”有什么用途?

  •  513
  • Head Geek  · 技术社区  · 16 年前

    这里有人用过C++的“placement new”吗?如果是这样,为什么?在我看来,它只对内存映射硬件有用。

    25 回复  |  直到 6 年前
        1
  •  1
  •   CPPCPPCPPCPPCPPCPPCPPCPPCPPCPP    4 年前

    Placement new允许您在已分配的内存中构造对象。

    当您需要构造一个对象的多个实例时,您可能希望这样做以进行优化,并且每次需要新实例时不重新分配内存会更快。相反,对可以容纳多个对象的内存块执行一次分配可能更有效,即使您不想一次使用所有对象。

    DevX给出了一个 good example :

    标准C++也支持布局 new操作符,它构造了一个 对象位于预分配的缓冲区中。这 在构建内存池时很有用, 垃圾收集器或只是当 性能和异常安全 至高无上(没有危险 内存分配失败 已分配,以及 在a上构造对象 预分配的缓冲区需要更少的时间):

    char *buf  = new char[sizeof(string)]; // pre-allocated buffer
    string *p = new (buf) string("hi");    // placement new
    string *q = new string("hi");          // ordinary heap allocation
    

    您可能还想确保关键代码的某个部分不会出现分配失败(例如,在起搏器执行的代码中)。在这种情况下,您可能希望更早地分配内存,然后在关键部分中使用placement new。

    新安置中的分配

    您不应该释放正在使用内存缓冲区的每个对象。相反,您应该只删除[]原始缓冲区。然后,您必须手动调用类的析构函数。有关这方面的好建议,请参阅Stroustrup的常见问题解答: Is there a "placement delete" ?

        2
  •  0
  •   CPPCPPCPPCPPCPPCPPCPPCPPCPPCPP    4 年前

    我们将其与自定义内存池一起使用。只是一个草图:

    class Pool {
    public:
        Pool() { /* implementation details irrelevant */ };
        virtual ~Pool() { /* ditto */ };
    
        virtual void *allocate(size_t);
        virtual void deallocate(void *);
    
        static Pool *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, ...);
    

    现在,您可以将对象聚集在一个内存竞技场中,选择一个非常快但不进行释放的分配器,使用内存映射,以及您希望通过选择池并将其作为参数传递给对象的放置新运算符来施加的任何其他语义。