这里有人用过c++的“placement new”吗?如果有,为什么?在我看来,它只在内存映射硬件上有用。
当前回答
我使用它来创建基于内存的对象,其中包含从网络接收到的消息。
其他回答
我使用它来构造通过alloca()分配到堆栈上的对象。
无耻的宣传:我在这里写过博客。
放置new允许在已经分配的内存中构造一个对象。
当您需要构造一个对象的多个实例时,您可能需要这样做以进行优化,并且在每次需要新实例时不重新分配内存会更快。相反,对可以容纳多个对象的内存块执行一次分配可能会更有效,即使您不想一次使用所有内存块。
DevX给出了一个很好的例子:
标准c++也支持放置 New操作符,它构造 对象在预先分配的缓冲区上。这 在构建内存池时很有用, 垃圾收集器或简单的什么时候 性能和异常安全是重要的 派拉蒙(没有危险 内存分配失败 已经分配了,然后呢 对象上构造对象 预分配缓冲区占用的时间更少):
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的常见问题:是否存在“位置删除”?
我认为任何答案都没有强调这一点,但新位置的另一个好例子和用法是减少内存碎片(通过使用内存池)。这在嵌入式和高可用性系统中特别有用。在最后一种情况下,这一点特别重要,因为对于一个必须运行24/365天的系统来说,没有碎片是非常重要的。此问题与内存泄漏无关。
Even when a very good malloc implementation is used (or similar memory management function) it's very difficult to deal with fragmentation for a long time. At some point if you don't manage cleverly the memory reservation/release calls you could end up with a lot of small gaps that are difficult to reuse (assign to new reservations). So, one of the solutions that are used in this case is to use a memory pool to allocate before hand the memory for the application objects. After-wards each time you need memory for some object you just use the new placement to create a new object on the already reserved memory.
这样,一旦应用程序启动,就已经预留了所需的所有内存。所有新的内存预留/释放都将分配到已分配的池中(您可能有几个池,每个池对应一个不同的对象类)。在这种情况下不会发生内存碎片,因为没有间隙,您的系统可以运行很长时间(数年)而不会出现内存碎片。
我在实践中看到过这种情况,特别是在VxWorks RTOS中,因为它的默认内存分配系统受到了很多碎片的影响。因此,通过标准的new/malloc方法分配内存在项目中基本上是被禁止的。所有的内存预留都应该到一个专用的内存池中。
它被std::vector<>使用,因为std::vector<>通常分配比vector<>中的对象更多的内存。
我们将它用于自定义内存池。简单介绍一下:
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操作符来施加的语义。
推荐文章
- decltype(auto)的一些用途是什么?
- Shared_ptr转换为数组:应该使用它吗?
- Printf与std::字符串?
- 禁用复制构造函数
- 只接受特定类型的c++模板
- c#和Java中的泛型有什么不同?和模板在c++ ?
- 为什么ARC仍然需要@autoreleasepool ?
- c++ 11中的递归lambda函数
- 在c++中指针使用NULL或0(零)吗?
- 在c++中,如何将int值附加到字符串中?
- 就性能而言,使用std::memcpy()还是std::copy()更好?
- 为什么布尔值是1字节而不是1位?
- 四舍五入到一个数字的最接近倍数
- 模板默认参数
- c++ auto关键字。为什么它是魔法?