在c++中使用new表达式时实际是执行了3步
1. new表达式调用一个名为 operator new(或者 operator new[])的标准库函数。该函数分配一块足够大的、原始的、未命名的内存空间以便存储特定类型的对象(或者对象数组)
2. 编译器运行相应的构造函数以构造这些对象,并为其传入初始值
3. 对象被分配了空间并构造完成,返回一个只想该对象的指针
使用delete表达式时实际执行了2步
1. 对指针所指向的对象或数组中的元素执行对应的析构函数
2. 编译器调用名为 operator delete(或者 operator delete[])的标准库函数释放内存空间
可以重载 operator new 和 operator delete 以达到控制内存分配的过程,但
void operator new(size_t, void);
是不允许重载的,只供标准库使用。(以上参考自c++ primer)
定位new允许我们在一个特定的、预先分配的内存地址上构造对象,一段简单的事例代码如下
#include <iostream>
#include <string>
int main()
{
static int a = 0xFF;
int b = 0xFF;
int *c = new int(0xFF);
auto aa = new(&a) int(3);
std::cout << &a << ","<<aa<< ","<<a << std::endl;
auto bb = new(&b) int(3);
std::cout << &b << "," << bb << "," << b << std::endl;
auto cc = new(c) int(3);//是c不是&c
std::cout << c << "," << cc << "," << *c << std::endl;
return 0;
}
运行结果如下
012F1000,012F1000,3
007FFC04,007FFC04,3
00CB3568,00CB3568,3
由此我们可以看出,定位new可以使用堆、栈和静态存储区。值得注意的是,用定位new实例化的类对象在不用时需要显示调用析构函数,但不会释放所在的内存空间。
在频繁创建和删除对象的时候提前开辟一大块内存区域,使用定位new在这里进行操作,或许可以在整体上避免一些内存碎片,并且提高创建的性能,不过怎么标识某块内存里的值已经无效可能还需要一番操作。