加载中...

C++ 之 new 的几种用法


运算符 new

new 最常的用法是作为运算符,这时候 new 会在堆上分配一块内存,并会自动调用类的构造函数,如:

string *str = new string("test new");

new 作为运算符时,它是 C++ 内置的,你不能对它做任何的改变,除了使用它。

函数 new

第二种用法是 new 函数,其实 new 作为运算符时,内部分配内存使用的就是 new 函数,其原型是:

void *operator new(size_t size);

new 函数返回的是一个 void 指针,指向一块未经初始化的内存。

可以发现,这和 C 语言的 malloc 行为相似,所以你可以重载new函数,并且增加额外的参数,但是必须保证第一个参数必须是 size_t 类型,它指明了分配内存块的大小。

如果重载了 new 函数,在使用 new 操作符时调用的就是你重载后的 new 函数了。

这时候使用 new 函数,和语句 string *str = new string("test new"); 相对的代码大概是如下的样子:

string *str = (string*)operator new(sizeof(string));
str.string("test new");  // 当然这个调用时非法的,但是编译器是没有这个限制的

placement new

placement new 其实也是 new 作为函数的一种用法,它允许你在一块已存在的内存上分配一个对象,而内存上的数据不会被覆盖或者被你主动改写。placement new 同样由 new 操作符调用,调用格式是:

new (buffer) type(size_t size);

先看看下面的代码:

char str[22];
int data = 123;
int *pa = new (&data) int;
int *pb = new (str) int(9);

结果为:

*pa = 123 // 未覆盖原数据)
*pb = 9    // 覆盖原数据

可以看到 placement new 并没有分配新的内存,也可以使用在栈上分配的内存,而不限于堆。

为了使用 placement new 你必须 #include <new>#include <new.h>

其实 placement new 和第二种用法一样,只不过多了参数,是函数 new 的重载,语法格式为:

void *operator new(size_t, void* buffer);

它看起来可能是这个样子:

void *operator new(size_t, void* buffer) { return buffer;}

和 new 对应的就是 delete 了。

总结

① 函数 new:

void *operator new(size_t size);  // 在堆上分配一块内存
placement newvoid *operator new(size_t, void* buffer);  // 在一块已经存在的内存上创建对象

如果你已经有一块内存,placement new 会非常有用,事实上,它在 STL 中有着广泛的使用。

② 运算符 new: 最常用的 new,没什么可说的。

③ 函数 new 不会自动调用类的构造函数,因为它对分配的内存类型一无所知;而运算符 new 会自动调用类的构造函数。

④ 函数 new 允许重载,而 运算符new 不能被重载。

⑤ new 对应的是 delete。


文章作者: EXP
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 EXP !
  目录