堆上内存分配的 new 运算符

29

我在查看 new 操作符的签名。它是:

void* operator new (std::size_t size) throw (std::bad_alloc);

但是当我们使用这个运算符时,我们从来没有用过强制类型转换。也就是说

 int *arr = new int;

那么,在这种情况下C++如何将类型为void*的指针转换为int*?因为即使malloc返回void*,我们仍需要明确使用类型转换。

2个回答

48
在C++中,operator newnew操作符之间有一个非常微妙的区别。(请再次阅读...顺序很重要!) operator new函数是C++中malloc函数的类比。它是一个原始内存分配器,其责任仅仅是生成一块内存来构建对象。它不会调用任何构造函数,因为这不是它的工作。通常情况下,在C++代码中你不会直接看到operator new的使用;它看起来有些奇怪。例如:
void* memory = operator new(137); // Allocate at least 137 bytes
new运算符是一个关键字,用于为对象分配内存并调用其构造函数。这在C++代码中最常见。当你写下以下代码时:
int* myInt = new int;

您正在使用new运算符来分配一个新的整数。在内部,new运算符的工作原理大致如下:
  1. 使用operator new分配内存以容纳所请求的对象。
  2. 调用对象构造函数(如果有)。如果这会引发异常,请使用operator delete释放上述内存,然后传播异常。
  3. 返回指向新构造对象的指针。
因为new运算符和operator new是分开的,所以可以使用new关键字来构造对象而不实际分配任何内存。例如,著名的placement new允许您在用户提供的内存中的任意内存地址上构建对象。例如:
T* memory = (T*) malloc(sizeof(T)); // Allocate a raw buffer
new (memory) T(); // Construct a new T in the buffer pointed at by 'memory.'

通过定义自定义的operator new函数重载new运算符,可以让您以这种方式使用new:您指定分配的方式,C++编译器将把它连接到new运算符中。
如果你好奇的话,delete关键字也是同样的道理。有一个叫做operator delete的释放内存的函数,还有一个负责调用对象析构函数和释放内存的delete运算符。但是,operator newoperator delete可以在这些上下文之外使用,例如代替C中的mallocfree

第二步应该是“调用对象构造函数(如果有)。如果这引发了任何异常,则释放上述内存并传播异常。” - GManNickG
@GMan- 感谢你发现了这个问题!是我的错。我会修复它的。 - templatetypedef
还有,您能向我推荐一些类似这样的珍珠般的书吗? - Chander Shivdasani
@Chander Shivdasani- 很高兴能帮忙;别忘了接受答案。;-) 这个智慧珠子基于Scott Meyers在《Effective C++,第3版》中对new的讨论,该书被广泛认为是C++最好的书之一。它将把你从一个优秀的C++编码人员转变为一个伟大的C++编码人员,并向你展示各种酷炫的想法,这些想法你从未想过可以用C++表达。我强烈推荐它。 - templatetypedef
非常感谢...我一定会得到一份副本。 - Chander Shivdasani

5

您把new表达式和operator new()函数混淆了。当编译器编译前者时,它会在其他内容中生成对operator new()函数的调用,并传递足以容纳new表达式中提到的类型的大小,然后返回该类型的指针。


给那位点了踩的人 - 这个回答有什么问题吗?它看起来完全正确。 - templatetypedef

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