C++学习之内存的分配和初始化

时间:2024-03-19 14:37:13

C++定义了2个运算符来分配和释放动态内存。new分配内存,delete释放内存。

1. 使用new动态分配和初始化对象

在*空间分配的内存是无名的,new返回一个指向分配的对象的指针。

	int *pi = new int; // pi指向一个动态分配的、未初始化的无名对象

默认情况下,动态分配的对象是默认初始化,内置类型(int, double)或组合类型(struct)的对象的值是未定义的,十分危险。类类型(vector、string)对象使用默认构造函数进行初始化。

	string *ps = new string; // string初始化为空
	int *pi = new int; // pi指向一个未初始化的int

使用圆括号对对象进行初始化

	int *q1 = new int(1024);  // q1指向的对象的值为1024
	string *ps = new string(10, '9'); // 初始化为"9999999999"

使用列表初始化(花括号)

	vector<int> *pv = new vector<int>{0,1,2,3,4,5,6,7,8,9};

对动态分配的对象进行值初始化,只需在类型名之后跟一对空括号即可

	string *ps1 = new string; // 默认初始化为空string
	string *ps2 = new string();  // 值初始化为空string
	int *pi1 = new int;   // 默认初始化,*pi1的值未定义
	int *pi2 = new int(); // 值初始化为0, *pi2为0

对于定义了自己的构造函数的类类型来说,对象都会通过默认构造函数进行初始化。而内置类型则不具备这个功能,需要我们对其初始化。
若我们提供了一个括号包围的初始化器,则可以使用auto根据初始化器来自动推断我们想分配的对象的类型。由于编译器要用初始化器的类型来推断要分配的类型,只有当括号中仅有单一初始化器时才可以使用auto:

auto p1 = new auto(pi1);    //  与pi1类型相同的对象,该对象用pi1进行初始化,p1是int *
auto p2 = new auto(pi1,pi2);  //  ERROR:括号中只能由单个初始化器

动态分配的const对象必须初始化

用new分配const对象。

	const int *pci = new const int(1024);   // 分配并初始化一个const int
	const string *pcs  = new const string;

若系统内存耗尽,则内存分配失败,new会抛出bad_alloc的异常。可以使用定位new来阻止抛异常:

	int *p3 = new (nothrow) int; // 若分配失败,new返回一个空指针

2、释放动态内存

动态内存使用完毕后,使用delete将内存归还给系统。delete执行2个动作:销毁给定的指针指向的对象;释放对应的内存。传递给delete的指针必须指向动态分配的内存或一个空指针。

	delete p3;

const对象的值不能被改变,但是其本身可以被销毁。

	const int *pci = new const int(1024);  // 分配并初始化一个const int
	delete pci;  // 释放一个const对象

动态对象的生存期

对于一个由内置指针管理的动态对象,直到被显式释放之前都是存在的。
动态内存的使用存在的三个常见问题:

  1. 忘记delete内存
  2. 使用已经释放的对象
  3. 同一内存多次释放

delete一个指针之后,指针值变得无效,但是很多机器上依然保存着动态内存的地址,指针变成了空悬指针:指向一块曾经保存数据但是现在已经无效的内存的指针。
避免空悬指针:在指针即将离开其作用域之前释放掉关联的内存,若需要保留指针,可以在delete之后将nullptr赋予指针,表明指针不指向任何对象。

使用智能指针可以避免这些问题。

3、shared_ptr和new的结合

若不初始化一个智能指针,则它会初始化为一个空指针,可以用new返回的指针来初始化智能指针。

	shared_ptr<double> p4;  // shared_ptr指向一个double

接收指针参数的智能指针构造函数是explicit的,不能将一个内置指针转换为智能指针,必须采用直接初始化:

	shared_ptr<int> p5 = new int(42); // ERROR
	shared_ptr<int> p5(new int(42)); // p2指向一个值为42的int

一个返回shared_ptr的函数不能在其返回语句中隐式转换一个普通指针:

shared_ptr<int> clone(int p){
	return new int(p);   // error: 隐式转换为shared_ptr<int>
}

shared_ptr<int> clone(int p){
	return shared_ptr<int>(new int(p)); // 正确:显式用int*创建shared_ptr<int>
}

一个用来初始化智能指针的普通指针必须指向动态内存,因为智能指针默认使用delete释放它关联的对象,可以将智能指针绑定到一个指向其他类型的资源的指针上。
C++学习之内存的分配和初始化
C++学习之内存的分配和初始化