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


当前回答

我们将它用于自定义内存池。简单介绍一下:

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, ...);

现在你可以将对象聚集在一个单独的内存区域中,选择一个非常快但不进行释放的分配器,使用内存映射,以及任何你希望通过选择池并将其作为参数传递给对象的放置new操作符来施加的语义。

其他回答

一般来说,放置新是为了摆脱“正常新”的分配成本。

我使用它的另一个场景是,我想要访问一个仍待构造的对象的指针,以实现每个文档的单例。

它可能在使用共享内存时很方便,在其他用途中…例如:http://www.boost.org/doc/libs/1_51_0/doc/html/interprocess/synchronization_mechanisms.html#interprocess.synchronization_mechanisms.conditions.conditions_anonymous_example

我用它创建了一个Variant类(例如,一个对象可以表示一个单独的值,这个值可以是许多不同类型中的一个)。

如果Variant类支持的所有值类型都是POD类型(例如int, float, double, bool),那么带标签的C风格的联合就足够了,但如果你想要一些值类型是c++对象(例如std::string), C的联合特性就不行,因为非POD数据类型可能不会被声明为联合的一部分。

因此,我分配了一个足够大的字节数组(例如sizeof(the_largest_data_type_I_support)),并使用placement new在该区域初始化适当的c++对象,当Variant被设置为持有该类型的值时。(当然,当切换到不同的数据类型时,我事先手动调用对象的析构函数)

这里是c++ in-place构造函数的杀手级用法:对齐缓存线,以及其他2边界的幂。以下是我的超快速指针对齐算法,使用5个或更少的单周期指令,达到2边界的任意幂:

/* Quickly aligns the given pointer to a power of two boundary IN BYTES.
@return An aligned pointer of typename T.
@brief Algorithm is a 2's compliment trick that works by masking off
the desired number in 2's compliment and adding them to the
pointer.
@param pointer The pointer to align.
@param boundary_byte_count The boundary byte count that must be an even
power of 2.
@warning Function does not check if the boundary is a power of 2! */
template <typename T = char>
inline T* AlignUp(void* pointer, uintptr_t boundary_byte_count) {
  uintptr_t value = reinterpret_cast<uintptr_t>(pointer);
  value += (((~value) + 1) & (boundary_byte_count - 1));
  return reinterpret_cast<T*>(value);
}

struct Foo { Foo () {} };
char buffer[sizeof (Foo) + 64];
Foo* foo = new (AlignUp<Foo> (buffer, 64)) Foo ();

这是不是让你的脸上露出了微笑(:)。我♥♥♥c++ 1x

The one place I've run across it is in containers which allocate a contiguous buffer and then fill it with objects as required. As mentioned, std::vector might do this, and I know some versions of MFC CArray and/or CList did this (because that's where I first ran across it). The buffer over-allocation method is a very useful optimization, and placement new is pretty much the only way to construct objects in that scenario. It is also used sometimes to construct objects in memory blocks allocated outside of your direct code.

我在类似的情况下使用过它,尽管它不经常出现。不过,它是c++工具箱中的一个有用工具。