为什么要显式地调用 operator new 函数?

21

我看到了这样的代码:

void *NewElts = operator new(NewCapacityInBytes);

而且匹配的调用明确地使用operator delete,稍后随之使用。

为什么要这样做而不是:

void *NewElts = new char[NewCapacityInBytes];

为什么要显式调用 operator newoperator delete


你可能会发现这个相关的问题很有趣:https://dev59.com/nUzSa4cB1Zd3GeqPpLwz - sharptooth
4个回答

32
显式调用 operator new 时,会调用全局的“原始” operator new。全局 operator new 返回一个原始的内存块,不调用对象的构造函数或任何用户定义的 new 的重载函数。因此,全局 operator new 基本上类似于 C 中的 malloc
因此:
// Allocates space for a T, and calls T's constructor,
// or calls a user-defined overload of new.
//
T* v = new T;

// Allocates space for N instances of T, and calls T's 
// constructor on each, or calls a user-defined overload
// of new[]
//
T* v = new T[N];

// Simply returns a raw byte array of `sizeof(T)` bytes.
// No constructor is invoked.
//
void* v = ::operator new(sizeof(T));

8
一个例子是实现内存池,你一次性分配一个大块内存,而内存池的用户将调用函数在这个内存块中创建对象,而不是使用 new。根据分配模式,这可以比 newdelete 提供更好的性能。 - Steve M
1
哦,有趣。我不知道 C++ 的 这个 角落。 - Paul Nathan
2
这个答案描述了operator new的作用,但它并没有解释为什么我们会使用operator new(N)而不是new char[N]。毕竟这就是问题所在。 - Rob Kennedy
我将这个问题理解为特别关注于char,你正在分配一个任意大小的字节块,而不是分配一个与某个特定类型T大小相同的块。你真的可以重载charoperator new吗? - Rob Kennedy
@Rob Kennedy:不,无法为特定的内置类型重载operator new - sharptooth
显示剩余2条评论

7

如果你写下:

T *p = new T;

这将分配足够的内存来容纳一个T,然后将T构造到其中。如果您写:

T *p = ::operator new(sizeof(T));

这将分配足够的内存来容纳一个T,但不会构造T。你可能在使用放置new的时候看到这种情况:

T *p = ::operator new(sizeof(T)); // allocate memory for a T
new (p) T; // construct a T into the allocated memory
p->~T(); // destroy the T again
::operator delete(p); // deallocate the memory

2

如果您使用operator new(bytesize)进行分配内存,那么您可以使用delete来释放它,而如果您通过new char[bytesize]进行分配,则必须使用delete[]进行匹配。尽可能避免使用delete[],这是一个可怕的做法。这很可能是使用operator new的根本原因。


3
如果使用全局的operator new来分配内存,就可以使用全局的operator delete来释放内存。但是全局的operator delete不会调用析构函数。因此,如果在调用全局的operator new之后实际上使用placement new构造了一个对象,那么仅靠全局的operator delete是不足以销毁该对象的。在释放内存之前,您需要显式地调用析构函数来销毁对象。本质上,全局的operator newoperator delete都允许您将存储分配/释放与对象初始化/销毁分离开来。 - Charles Salvia
@Charles:他没有使用placement new,那个内存也不需要析构。作为一种纯粹分配内存的形式,operator new()是最安全的选择,因为它不需要烦人的delete[]或者不寻常的free()来释放内存。 @Steve:delete[]是一种可恶的东西,因为它是不必要的。当你使用operator new而不是new[]时,并不意味着堆就神奇地不需要存储块的大小或其他任何东西。 - Puppy

1

当您想要分配一块“原始”内存块并且不希望在该内存中构造任何内容时,请使用它。

分配一块原始内存块和“构造”一个字符数组之间几乎没有实际区别,但是使用operator new明确地向任何阅读代码的人传达了您的意图,这非常重要。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接