静态内存用来保存局部static对象、类static数据成员以及定义在任何函数之外的变量。栈内存用于保存在函数体内的非static对象。分配在静态或栈内存中的对象由编译器自动创建或销毁。对于栈对象,仅在其定义的程序块运行时才存在;static对象在使用之前分配,在程序结束时销毁
除了静态内存和栈内存,每个程序还拥有一个内存池。这部分内存被称作自由空间或堆。程序用堆来存储动态分配的对象—(那些在程序运行时分配的对象)。动态对象的生存期由程序来控制,也就是说,当动态对象不再使用时,我们的代码必须显示地销毁它。
在c++中,动态内存的管理是通过一对运算符来完成的:new,在动态内存中为对象分配空间并返回一个指向该对象的指针
delete,接受一个动态对象的指针,并销毁该对象,释放与之关联的内存。
新的标准库提供了两种智能指针类型来管理动态对象。智能指针的行为类似常规指针,重要的区别是它负责自动释放所指向的对象(特别注意的是有一种情况,如果是自己new的指针,在delete之前代码抛出了异常,则这个时候内存并不会被释放;而对于智能指针,它还是能够自动释放)。新标准库提供的这两种智能指针的区别在于管理底层指针的方式:
share_ptr 允许多个指针指向同一对象;
unique_ptr则“独占”所指向的对象;
标准库还定义了一个名为weak_ptr的伴随类,它是一种弱引用,指向share_ptr所管理的对象。这三种类型都定义在memory头文件中。
一、shared_ptr类
类似vector,智能指针也是模板,因此当我创建一个智能指针的时候,必须提供一些额外的信息(指针可以指向的类型)。与vector一样,我们在尖括号内给出类型,之后是所定义的这种智能指针的名字。
shared_ptr <string> p1; //shared_ptr可以指向string
shared_ptr <list<int>> p2; //shared_ptr可以指向int的list
(默认初始化的智能指针中保存着一个空指针)
智能指针的使用方式与普通指针类似,解引用一个智能指针,能返回一个它指向的对象
例子:if (p1 && p1->empty()) //如果p1的值不为空,检查他是否指向一个空string
*p1=”hi” ; //如果p1不为空,还指向一个空string,就赋一新值给它。
make_shared函数
最安全的分配使用动态内存的方法是调用一个名为make_shared的标准库函数。这个函数可以在动态内存中分配一个对象并初始化它,返回指向此对象的share_ptr。
shared_ptr<int> pp1 = make_shared<int> (7);
由于最后一个shared_ptr销毁之前,内存都不会被释放,因此,确保了某个share_ptr不再会被使用的话,应该用erase删除它。
程序使用动态内存出于一下三种原因之一:
1、程序不知道自己需要使用多少对象.
2、程序不知道所需对象的准确类型。
3、程序需要在多个对象间共享数据。
二、unique_ptr类
与share_ptr不同,任意时刻只能有一个unique_ptr指向给定的对象,当unique_ptr被销毁时,它所指向的对象也被销毁。
与与share_ptr不同,没有类似make_shared的标准库函数返回一个unique_ptr。我们定义一个unique_ptr时,需要将他绑定到一个new返回的指针。初始化时,必须采用直接初始化。
unique_ptr<double> p1;//可以指向一个double的unique_ptr
unique_ptr<int> p2(new int (42));//p2指向一个值为42的int
get用来将指针的访问权限传递给代码,只有在确定代码不会delete指针的情况下,才能使用get。特别是,永远不要用get初始化另一个智能指针或者为另一个智能指针赋值。
用智能指针时,必须遵守:
1、不使用相同的内置指针值初始化(或reset)多个智能指针
2、不delete get()返回的指针
3、不适用get()初始化或reset另一个智能指针。
4、如果你使用get()返回的指针,记住当最后一个对应的指针指针销毁后,你对应的指针就变为无效了
5、如果你使用智能指针管理的资源不是new分配的内存,记住传递给它一个删除器。
三、weak_ptr类
weak_ptr是一种不控制所指向对象生存期的智能指针,它指向由一个share_ptr管理的对象。将weak_ptr绑定到一个shared_ptr不会改变share_ptr的引用次数。一旦最后一个指向对象的shared_ptr被销毁,对象就会被释放。即使有weak_ptr指向对象,对象也还是会被释放,因此,weak_ptr的名字抓住了这种智能指针”弱”共享对象的特点。
shared_ptr p1 = make_shared(65); weak_ptr p2(p1); //p1.reset(); if (shared_ptr np = p2.lock()) { cout << *np << endl; } else { cout << "用不了诶" << endl; }
由于对象可能不存在,不能直接使用weak_ptr访问对象,而必须调用lock。此函数会检查weak_ptr指向的对象是否仍然存在。如果存在则返回一个指向共享对象的share_ptr。
四、C++内存模型
C++内存模型可分为四个部分,代码区、全局区、栈区、堆区
代码区:保存函数体的二进制代码,由操作系统管理
全局区:保存全局变量、静态变量、常量,在程序运行周期一直存在
栈区:保存函数的局部变量,形参等,由编译器去进行数据的保存和释放
堆区:程序员自由申请释放的内存空间,如果忘记释放,将在程序运行结束后由系统回收