c ++ placement new和overloading new

时间:2011-01-09 09:05:54

标签: c++ memory-management operator-overloading

关于SO的许多问题询问有关C ++的新功能(example 1example 2)的原因。许多答案都说 - 自定义分配对象,如预先分配的空间。

但问题是 - 为什么需要为此安排新的?不仅仅是运营商的新超载足够吗?通过重载运算符new for class I可以精确控制从哪里获取内存 - 比如调用自定义分配器。那么为什么我需要为此目的安置新的?

4 个答案:

答案 0 :(得分:8)

Placement New

最好的例子是考虑std :: vector

std :: vector如何将新项目放入数组?

在向量的末尾添加新元素时,必须使用新的位置。

class MyVector
{
    char*  data;
    size_t size;

    MyVector() : size(0), data(new char[1000]) {}

    // Placement new copy construction of element into array.
    void push_back(T const& t) { new (data + (sizeof(T) * size)) T(t); ++size;}
};

记住你不能使用赋值或简单的副本,因为数组中尚不存在元素(即内存空间还不是T(它的值未定义))所以你必须新建一个新的T数组中的对象。

因此,将new放置为创建容器对象的方法。您可以分配比容器所需的空间更多的空间(而不是初始化它)。然后使用placement new来初始化添加的元素。

重载新

重载new允许您控制对象具有dynamic storage duration时使用的空间。也许您的预期使用模式不属于正常使用模式,您希望优化创建/销毁。也许你想要构建自己的垃圾收集(对于特定类型)。

主要的不同之处在于:

  • 重载新控件为“动态存储持续时间”对象创建空间。
  • Placement new可以用于动态和自动存储持续时间对象(我想也是静态的)。并在外部用于管理对象。

概述:

两者都是该语言的极端情况,很少在普通代码中使用(我想我已经编写了2个新的重载和一个使用贴片新的类(对于真实的生产代码/不包括实验和测试),在15年内)。

当您需要在现实生活中使用这些结构时,您将与经验丰富的团队合作数年,以验证您的设计。

答案 1 :(得分:6)

你认为两者都可以用于解决同一类问题是正确的,但你缺少的是运算符新的重载是侵入性的(分配策略对象中),而放置新的不是(分配策略完全独立)。

Martin York的回答在这方面提供了一个很好的例子:std::vector<>拥有自己的分配策略,而不对类型T添加任何要求。

答案 2 :(得分:0)

就像上面链接中所说的其他海报一样,placement new会将一个对象放在已经分配的内存上。

为类(或全局)重载operator new将始终从空闲列表(malloc或new)中获取内存。当然,自定义分配器可以使新运算符重载,使其在内部使用placement new。

但我还是没有看到操作员new如何作为替代¨placementnew? : - )

此外,由于这个问题的主题有关键词¨versus¨,我认为它们是放置new和operator new之间的比较概念。有了这种认识,请注意,通过placement new分配的对象需要一种不同的策略“修改它”:必须手动调用该对象上的析构函数。 (当程序员被要求手动调用析构函数时,这是语言中唯一的发生率)。在重载operator new的情况下,如果由程序员提供,则将调用重载删除。他们在这里没有强制要求手动调用析构函数:一个简单的“删除对象”¨会做到这一点。

对不起详细的回答,但我希望你明白这一点。

答案 3 :(得分:-1)

在自定义分配器中,由于性能的原因,您最好使用placement new以自定义方式管理一个大的预分配缓冲区。标准堆实现速度非常慢,如果分配/解除分配大量相同大小的对象,自定义实现可能会快1000倍(不夸大)

新的慢速的主要原因是它必须是线程安全的。因此,每次访问堆都必须同步,这意味着如果您有不同的线程经常分配/解除分配,您将遇到性能下降。在堆中搜索块也不是一项便宜的任务。

如果您知道所有已分配的块的大小相同,那么使用placement new的自定义实现可以更快。