c++放置新与重载新
SO 上的许多问题都询问有关 C++ 的放置新功能(示例 1,示例 2)为什么使用它。许多答案都说 - 自定义分配对象,例如在预先分配的空间中。
但问题是 - 为什么需要为此放置新的位置?仅仅为类重载运算符 new 还不够吗?通过类的重载运算符 new,我可以精确控制从何处获取内存 - 就像调用自定义分配器一样。那么为什么我需要为此目的安置新的呢?
Many questions on SO ask about placement new feature of C++ (example 1, example 2) why it is used for. Many answers saying - custom allocating of objects like in pre-allocated spaces.
But question is - why need placement new for this? Won't just overload of operator new for class enough? By overload operator new for class I can exactly control where memory taken from - like call custom allocator. So why would I need placement new for this purpose?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
放置新
最好的例子是考虑 std::vector
std::vector 如何将新项目放入数组中?
当您将新元素添加到向量的末尾时,它必须使用新的放置。
请记住,您不能使用赋值或简单复制,因为该元素尚未存在于数组中(即内存空间还不是 T(其值未定义)),因此您必须 new 来在数组中创建一个新的 T 对象大批。
因此,可以将放置 new 视为创建容器对象的一种方法。您可以分配比容器所需更多的空间(而不是初始化它)。然后使用placement new 在添加元素时对其进行初始化。
重载 new
重载 new 允许您控制对象具有
动态存储持续时间
时使用的空间。也许您预期的使用模式不属于正常使用模式,并且您想要优化创建/销毁。也许您希望构建自己的垃圾收集(针对特定类型)。主要区别在于:
概述:
两者都是该语言的极端情况,很少在普通代码中使用(我想我在 15 年内编写了 2 个新的重载和一个使用新放置的类(对于真正的生产代码/不包括实验和测试)。
当您需要在现实生活中使用这些构造时,您将已经与经验丰富的团队合作了几年,可以验证您的设计。
Placement New
Best example is to think about std::vector
How does std::vector put new items into an array?
When you add a new element to the end of an vector it must use placement new.
Remember you can not use assignment or a simple copy because the element does not yet exist in the array (ie the memory space is not yet a T (its value is not defined)) so you must new to create a new T object in the array.
So think of placement new as a means of creating container objects. You can allocate more space than required for the container (and not initialize it). Then use placement new to initialize the elements as they are added.
Overload new
Overloading new allows you to control the space used when object have
dynamic storage duration
. Maybe your expected usage patterns do not fall under the normal usage patterns and you want to optimize creation/destruction. Maybe you want you want to build your own garbage collection (for a particular type).The main different is that:
Overview:
Both are corner cases for the language and rarely used in normal code (I think I have written 2 new overloads and one class that uses placement new (for real production code/ does not include experiments and testing) in 15 years).
By the time you need to use these constructs in real life you will have been working with an experienced team for a couple of years that can validate your design.
您认为两者都可以用于解决同一类别的问题是正确的,但您缺少的是运算符 new 重载是侵入性的(分配策略在对象中),而放置 new 则不是't(分配策略完全独立)。
Martin York 的回答在这方面提供了一个很好的例子:
std::vector
拥有自己的分配策略,而不对类型T
添加任何要求。You are correct in thinking that both can be used to solve a same category of problems, but what you are missing is that operator new overloading is intrusive (allocation strategy is in the object), while placement new isn't (allocation strategy is completely independent).
Martin York's answer provides a great example in this regard :
std::vector<>
holds its very own allocation strategy without adding any requirement on the typeT
.就像其他发帖者在上面的链接中所说的那样,placement new 会将一个对象放置在已经分配的内存上。
类(或全局)的重载运算符 new 将始终从空闲列表(malloc 或 new)中获取内存。当然,自定义分配器可以重载 new 运算符,使其在内部使用新的放置。
但无论如何我不明白operator new 如何能够替代“placement new”。 :-)
另外,由于这个问题的主题有关键字“versus”,我认为它们是placement new和operator new之间比较的概念。认识到这一点,请注意,通过放置 new 分配的对象需要一种不同的“销毁”策略:必须手动调用该对象的析构函数。 (当程序员被强制手动调用析构函数时,这是该语言中唯一发生的情况)。在重载的operator new的情况下,如果程序员提供了重载的delete,那么将会调用重载的delete。不过,这里没有强制要求手动调用析构函数:一个简单的“删除 obj;”就可以解决问题。
很抱歉回答很冗长,但我希望你明白这一点。
Like other posters has said in the above links, placement new will place an object on an already allocated memory.
Overloading operator new for a class (or globally) will always take the memory from free list (either malloc or new). Of course, custom allocator can overload the new operator in such a way that it would use placement new internally.
But I do not see anyway how operator new can work as a replacement for ¨placement new¨. :-)
Also, since the subject of this question has keyword ¨versus¨, I reckon their is a notion of comparison between placement new and operator new. With that cognisance, please note that an object allocated via placement new necessitates a different strategy of ¨destructing¨ it: one must call the call the destructor on that object manually. (this is the only incidence in the language when programmer is mandated to call the destructor manually). In the case of overloaded operator new, an overloaded delete will be called, if supplied by the programmer. Their is no mandation here to call the destructor manually though: a simple ¨delete obj;¨ would do the trick.
Sorry for verbose answer but I hope you get the point.
在自定义分配器中,由于性能原因,您最好使用新的布局以自定义方式管理一个大的预分配缓冲区。标准堆实现非常慢,如果您分配/释放大量相同大小的对象,自定义实现可能会快 1000 倍(毫不夸张)
new 缓慢的主要原因是它必须是线程安全的。因此,对堆的每次访问都必须同步,这意味着如果您有不同的线程经常分配/释放,您将遇到性能下降。此外,在堆中搜索块也不是一项便宜的任务。
例如,如果您知道所有分配的块都具有相同的大小,则使用新放置的自定义实现会更快。
In custom allocators you'll be better off using the placement new to manage one big pre-allocated buffer in your custom way because of the performance. The standard heap implementation is horribly slow and if you allocate/deallocate a lot of objects of the same size a custom implementation might be a factor 1000 faster (without exaggerating)
The main reason for new for being slow is that it must be thread safe. So each access to the heap must be synchronized, what means if you have different threads often allocating/deallocating you will experience performance degradation. Also searching for blocks in the heap is not a cheap task.
A custom implementation with the placement new can be much faster if you know that all allocated blocks will be of the same size for example.