用于堆内存分配的新运算符

Posted

技术标签:

【中文标题】用于堆内存分配的新运算符【英文标题】:new operator for memory allocation on heap 【发布时间】:2011-06-23 22:19:12 【问题描述】:

我正在查看 new 运算符的签名。即:

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

但是当我们使用这个操作符时,我们从不使用强制转换。即

 int *arr = new int;

那么,在这种情况下,C++ 如何将void* 类型的指针转​​换为int*。因为,即使malloc 返回void*,我们也需要显式使用强制转换。

【问题讨论】:

【参考方案1】:

operator newnew 运算符在 C++ 中存在非常细微的区别。 (再读一遍……顺序很重要!)

函数operator new 是C 的malloc 函数的C++ 模拟。它是一个原始内存分配器,其职责仅是生成一块用于构造对象的内存块。它不调用任何构造函数,因为那不是它的工作。通常,您不会看到在 C++ 代码中直接使用operator new;看起来有点奇怪。例如:

void* memory = operator new(137); // Allocate at least 137 bytes

new 运算符是一个关键字,负责为对象分配内存并调用其构造函数。这是 C++ 代码中最常见的情况。当你写

int* myInt = new int;

您正在使用 new 运算符分配一个新整数。在内部,new 运算符的工作方式大致如下:

    使用operator new分配内存来保存请求的对象。 调用对象构造函数,如果有的话。如果这引发异常,请使用 operator delete 释放上述内存,然后传播异常。 返回一个指向新建对象的指针。

因为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

【讨论】:

第二步应该是“调用对象构造函数,如果有的话。如果这抛出任何异常,释放上面的内存并传播异常。” @GMan- 感谢您发现这一点!我的错。我会解决的。 另外,你能推荐一些我能找到这样珍珠的书吗? @Chander Shivdasani- 很高兴为您提供帮助;不要忘记接受答案。 ;-) 这颗智慧之珠基于 Scott Meyers 对“Effective C++, 3rd Edition”中新内容的讨论,该书被广泛认为是 C++ 方面最好的书籍之一。它将把你从一个优秀的 C++ 编码员转变为一个伟大的 C++ 编码员,并让你接触到各种你从未想过可以用 C++ 表达的酷想法。我强烈推荐它。 非常感谢...我一定会得到它的副本。【参考方案2】:

您将new 表达式与operator new() 函数混淆了。当前者被编译时,编译器会生成一个对operator new() 函数的调用,并传递足够的大小来容纳new 表达式中提到的类型,然后返回该类型的指针。

【讨论】:

致那些投反对票的人——这个答案有什么问题?这似乎完全正确。

以上是关于用于堆内存分配的新运算符的主要内容,如果未能解决你的问题,请参考以下文章

C++动态内存

内存分配的运算符重载?

如果已知 void* 分配大小,如何将确切的内存大小传递给 free()

4-数组指针与字符串1.4-动态内存分配

比较运算符compareTo()equals()==之间的区别与应用总结

新分配堆内存的初始内容(VS2010)