C++ new运算符

一、new运算符初始化

C++ 98 如何初始化动态分配的变量?
如果为内置的标准类型分配存储空间并初始化,可在类型名后面加上初始值,并将其用括号括起,如下:

int *pi = new int(10);				// pi初始化设置成10
double *pd = new double(99.99);		// pd初始化设置成99.99

这种括号语法也可用于有合适构造函数的类。

C++11 增加初始化动态分配变量的初始化方式:
初始化常规结构或数组,使用大括号列表初始化方式,如下:

struct where 
{
	double x;
	double y;
	double z;
};

where *one = new where { 2.5, 5.3, 7.2};
int *ar = new int[4] {2, 4, 6 ,8};

还可将列表用于单值变量初始化,如下:

int *pin = new int {6};
double *pdo = new double {99.99};

二、new失败

new可能找不到请求的内存量。C++刚开始的10年时,是让new返回空指针;但现在将引发异常std::bad_alloc。(后期再详细描述)

三、new:运算符、函数与替换函数

(1)运算符new和new[]分别调用如下函数,这些函数被称为分配函数,它们位于全局名称空间中:

void* operator new(std::size_t);	// 用于new
void* operator new[](std::size_t);	// 用于new[]

举例说明new运算符使用时调用的new()函数,如下:

// 第一种
int *pi = new int;
// 实际转换为:
int *pi = new(sizeof(int));

// 第二种
int *pa = new int[40];
// 实际转换为:
int *pa = new(40 * sizeof(int));

(2)运算符delete和delete[]则分别调用如下函数:

void operator delete(void *);
void operator delete[](void *);

举例说明delete运算符使用时调用的delete()函数,如下:

delete pi;
// 实际转换为
delete(pi);

四、定位new运算符

简介:
new运算符另一种使用: 被称为定位new运算符,它让程序员指定要使用的位置。程序员可以使用这种特性来设置其内存管理规程、处理需要通过特定地址访问的硬件或在特定位置创建对象。

使用方式:
(1)首先包含头文件,它提供了这种版本的new运算符的原型
(2)然后将new运算符用于提供了所需地址的参数。除需要指定参数外,句法与常规new运算符相同

具体使用方式如下述代码所示:

#include <new>

struct chaff
{
	char dross[20];
	int slag;
};

char buffer1[50];
char buffer2[500];

void test()
{
	chaff *p1;
	int *p2;
	
	p1 = new (buffer1) chaff;
	p2 = new (buffer2) int[20];
}

上述代码中的定位new运算符从buffer1中分配空间给了结构体chaff,从buffer2中分配空间给了一个包20个元素的int数组。

扩展:
定位new运算符的另一种用法: 将其与初始化结合使用,从而将信息放在特定的硬件地址处。
定位new运算符工作原理: 基本上它只是返回传递给它的地址,并将其强制转换为 (void *),以便能够赋给任何指针类型。这里说的是默认定位new函数,C++允许程序员重载定位new函数。
定位new函数: 定位new函数不可替换,但可重载。

举例说明定位new运算符使用时调用的new()函数,它是调用一个接收两个参数的new()函数,如下:

int *pi = new int;					// 调用 new(sizeof(int))
int *p2 = new (buffer) int;			// 调用 new(sizeof(int), buffer)
int *p3 = new (buffer) int[40];		// 调用 new(40 * sizeof(int), buffer)