new
运算符除了分配内存和调用构造函数之外还有什么其他的东西?
答案 0 :(得分:16)
C ++标准可以说明<new>
标题中新运算符的单个对象形式(通常使用的形式):
必需的行为:
将一个非空指针返回到适当对齐的存储(3.7.3),否则抛出一个 bad_alloc异常。此要求绑定在此函数的替换版本上。
默认行为:
- 执行循环:在循环内,函数首先尝试分配所请求的存储。是否 该尝试涉及调用标准C库函数malloc未指定。
- 如果尝试成功,则返回指向已分配存储的指针。否则,如果是最后一个参数 set_new_handler()是一个空指针,抛出bad_alloc。
- 否则,该函数调用当前的new_handler(18.4.2.2)。如果被调用的函数返回,则循环 重复。
- 当尝试分配所请求的存储成功或被调用时,循环终止 new_handler函数不会返回。
该标准还有很多关于新运算符和动态内存分配的其他内容(非常多),但我认为“默认行为”列表很好地总结了新运算符的基础知识。 / p>
答案 1 :(得分:9)
我已经在this回答中解释了它的作用。它解释了如何
new
获取内存new
处理内存故障new
处理构造函数异常new
处理特殊展示位置和非展示版本 Michael解释了默认分配器函数(:: operator new)如何很好地获取内存以及它如何处理失败。我已经在他的评论中看到了关于对象大小存储位置的问题。答案是,如果不是必要的话,没有存储大小。请记住,C不需要free
的大小(并且:: operator new只能使用malloc
):
void * memory = malloc(x);
free (memory); // no need to tell it the size
下面是一个示例,您可以看到存储大小如何影响新表达式数组形式的分配大小(我的其他答案未涵盖):
#include <cstddef>
#include <iostream>
struct f {
// requests allocation of t bytes
void * operator new[](std::size_t t) throw() {
void *p = ::operator new[](t);
std::cout << "new p: " << p << std::endl;
std::cout << "new size: " << t << std::endl;
return p;
}
// requests deleting of t bytes starting at p
void operator delete[](void *p, std::size_t t) throw() {
std::cout << "delete p: " << p << std::endl;
std::cout << "size : " << t << std::endl;
return ::operator delete[](p);
}
};
int main() {
std::cout << "sizeof f: " << sizeof (f) << std::endl;
f * f_ = new f[1];
std::cout << "&f_ : " << f_ << std::endl;
delete[] f_;
}
它会打印出这样的内容:
sizeof f: 1
new p: 0x93fe008
new size: 5
&f_ : 0x93fe00c
delete p: 0x93fe008
size : 5
对象本身的一个字节和计数的4个字节,它存储在对象的分配区域之前。现在,如果我们使用没有size参数的deallocation函数(只是从运算符delete中删除它),我们得到这个输出:
sizeof f: 1
new p: 0x9451008
new size: 1
&f_ : 0x9451008
delete p: 0x9451008
这里的C ++运行时并不关心大小,所以它不再存储它。请注意,这是高度特定于实现的,这就是gcc在这里能够告诉您成员运算符delete的大小。其他实现可能仍然存储大小,并且很可能如果存在要为类调用的析构函数。例如,只需在上面添加~f() { }
就可以使gcc存储大小,无论我们编写什么解除分配函数。
答案 2 :(得分:0)
取决于它是否过载,如果你构建应用程序进行调试,如果你正在使用内存泄漏检测器,如果你有某种内存池方案,如果你有类似Boehm垃圾收集器的标记/取消标记位等等。它可以在里面做很多自定义的东西,或者根本没什么特别的。