第12章 动态内存

第12章 动态内存

动态内存的对象的生存期与它们在哪里创建是无关的,只有当显式地被释放时,这些对象才会销毁。

为了更安全地使用动态对象,标准库定义了两个智能指针类型来管理动态分配的对象。

当一个对象应该被释放时,指向它的智能指针可以确保自动地释放它。

静态内存用来保存局部static对象、类static数据成员以及定义在任何函数体之外的变量。

栈内存用来保存定义在函数体内的非static对象。

分配在静态或栈内存中的对象由编译器自动创建和销毁。

static对象在使用之前分配,在程序结束时销毁。


12.1 动态内存与智能指针

new在动态内存中为对象分配空间并返回一个指向该对象的指针,我们可以选择对对象进行初始化;

delete接受一个动态对象的指针,销毁该对象,并释放与之关联的内存

为了更容易地使用动态内存,新的标准库提供了两种智能指针类型来管理动态对象。

shared_ptr允许多个指针指向同一个对象

unique_ptr则“独占”所指向的对象

标准库还定义了一个名为weak_ptr的伴随类,它是一种弱引用,指向shared_ptr所管理的对象。

三种类型都定义在memory头文件中

12.1.1 shared_ptr类

image-20220223105520254

make_shared函数
shared_ptr<int> p3 = make_shared<int>(42);  //指向一个值为42的int的shared_ptr
shared_ptr<string> p4 = make_shared<string>(10, '9');
shared_ptr<int> p5 = make_shared<int>();
shared_ptr的拷贝和赋值
auto p = make_shared<int>(42);
auto p(q); //p和q指向相同对象,此对象有两个引用者
auto r = make_shared<int>(42);
r = q;
//给r赋值,令它指向另一个地址
//递增q指向的对象的引用计数
//递减r原来指向的对象的引用计数
//r原来指向的对象已没有引用者,会自动释放

12.1.2 直接管理内存

string *ps = new string;   //初始化为空string
int *pi = new int;         //pi指向一个未初始化的int
int *pi = new(1024);
int *ps = new string(10, '9');
vector<int> *pv = new vector<int>{0,1,2,3,4,5,6,7,8,9};
string *ps1 = new string;
string *ps2 = new string();
int *pi1 = new int;    //默认初始化 *pi1的值未定义
int *pi2 = new int();  //值初始化为0 *pi2为0
auto p1 = new auto(obj);
auto p2 = new auto{a,b,c};  //错误
const int *pci = new const int(1024);
const string *pcs = new const string;

传递给delete的指针必须指向动态分配的内存,或者是一个空指针

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

const int *pci = new const int(1024);
delete pci;
int *p(new int(42));
auto q = p;  //pq指向相同的内存
delete p;  //p和q均变为无效
p = nullptr;

12.1.3 shared_ptr和new结合使用

shared_ptr<double> p1;
shared_ptr<int> p2(new int(42));

我们不能将一个内置指针隐式转换为一个智能指针

shared_ptr<int> p1 = new int(1024);  //错误:必须使用直接初始化形式
shared_ptr<int> p2(new int(1024));   //正确:使用了直接初始化
shared_ptr<int> clone(int p){
    return new int(p);   //错误:隐式转换
}

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

image-20220223120921026

image-20220223120929627

12.2 动态数组

int *p = new int[42];

初始化动态分配对象的数组

int *pia = new int[10];            //10个未初始化的int
int *pia2 = new int[10]();         //10个值初始化为0的int
string *psa = new  string[10];     //10个空string
string *psa2 = new string[10]();   //10个空string

初始化器初始化:

int *pia3 = new int[10]{0,1,2,3,4,5,6,7,8,9};
string *psa3 = new string[10]{"a", "an", "the"};  //初始化前几个

释放动态数组

delete [] pa;   //pa必须指向一个动态分配的数组或为空
typedef int arrT[42];   //arrT是42个int的数组的类型别名
int *p = new arrT;      //分配一个42个int的数组,p指向第一个元素
delete [] p;   //方括号是必须的,

空悬指针

在delete之后,指针就变成了空悬指针。即指向一块曾经保存数据对象但现在已经无效的内存的指针。

可以在delete之后将nullptr赋予指针,这样就清楚地指出指针不指向任何对象。

12.2.2 allocator类

在这里插入图片描述

allocator分配未构造的内存

当我们用完对象后,必须对每个构造的元素调用destroy来销毁它们。

在这里插入图片描述

//分配比vi中元素所占用空间大一倍的动态内存
auto p = alloc.allocate(vi.size() * 2);
//通过拷贝vi中的元素来构造从p开始的元素
auto q = uninitialized_copy(vi.begin(), vi.end(), p);
//将剩余元素初始化为42
uninitialized_fill_n(q. vi.size(), 42);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zdb呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值