一、前言
一般的对象随着其块的结束,其生命周期也会自动终结(被编译器在内存中销毁)。
C++中除了自动的和静态对象外,还提供动态内存管理。
二、动态内存
静态内存用来保存局部静态对象和类静态对象数据成员以及定义在函数外的变量(全局变量);栈内存用来保存定义在函数内的非静态对象,定义在静态内存和栈中的对象由编译器自动创建和销毁。对于栈对象,程序块运行时才存在;Static对象(静态对象)则在使用前分配,在程序结束时销毁。
何时使用之:
1.程序不知道需要使用对象的数目。
2.程序不知道对象的类型。
3.程序需要在多个对象间共享数据。
在C++中,动态内存管理通过new和delete完成。
三、new与delete
两个运算符分别负责分配和释放动态内存。
3.1 new
new返回一个指向所分配的对象的指针。
使用:
string *re = new string(10, "考研上岸"); //传统的值初始化
int *pt = new int(914);
vector<int> *prt = new vector<int>{9, 1, 4} //新标准下的列表初始化(花括号)
还可以使用auto关键字,让初始化器自己推断想要分配的对象的类型,要求括号中只有单一初始化器。
auto p1 = new auto('thu');
3.2 内存耗尽
如果分配失败,new会抛出一个std::bad_alloc的异常,这种类型定义在头文件new中。
3.3 Delete
delete接受一个指针,释放该指针指向的对象。
要注意的是该指针必须指向new分配的内存,释放一个非NEW分配的内存或者多次释放相同指针,其行为是未定义的。
很多时候调用者忘记释放内存,由内置指针管理的动态内存在被显示释放前会一直存在。
3.4 使用new和delete这组内置指针进行动态内存管理存在的问题
1.忘记delete内存
如果new和delete之间出现异常,其他函数中没有delete该位置的指针,其内存将永远不会被释放。
2.使用已经释放的对象(悬空指针)
该情况通常发生在多个指针指向同一对象,使用了delete以后两指针同时失效,查找指向相同内存的指针非常困难。
3.同一块内存多次释放
四、智能指针
为了更加容易和安全地使用动态内存,新标准,提供两种智能指针和一个伴随类,三种类型都定义在memory头文件中。
4.1 shared_ptr类
和vector模板一样,需要提供所指向的类型,其使用形式和普通指针类似。
如shared_ptr<string> re;
*re为解引用得到其所指对象
re->school等于(*re).school
最安全分配和使用动态内存的方式是调用make_shared的标准库函数,返回指向该对象的shared_ptr,也定义在头文件memory中。定义方式是模板一样,如:
shared_ptr<string> re = make_shared<string>(10, '考研上岸');
也可以用auto关键字更简单。
提供一个成员函数叫做构析函数负责对象的销毁,当指向该对象的指针数目为零时,则构析函数会销毁该对象,释放其动态内存空间。
因此,当离开作用域后,如果还有其他的shared_ptr指向该对象,该对象将不会被释放,这和静态对象不同。
4.2 unique_ptr
与shared_ptr不同,该类独自拥有其指向的对象,任意时刻只能有一个unique_ptr指向某一对象。
unique_ptr<string>(new string("立刻推:继续考研"));
该对象在一般情况下不支持拷贝和赋值。
可以通过调用release和reset将指针的所有权从一个(非const)unique_ptr转移给另一个,如:
unique_ptr<string>p2(p1.release());
调用release会切断与原来对象的联系,通常用于初始化另一个智能指针或对另一个智能指针赋值。
从函数可以返回unique_ptr,也可以返回一个局部对象的拷贝,编译器指导要返回的对象即将销毁,会执行一种特殊的拷贝。
ok,今天的内容到此结束。
欢迎收藏无神一起学习机器学习、Pytorch和C++,码字不易,点赞收藏加关注。