C++之动态内存

12 动态内存

12.1动态内存与智能指针

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

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

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

12.1.1 shared_ptr类

shared_ptr<string> p1; //默认初始化的智能指针保存空指针

使用时判断是否为空

if(p1 && p1->empty())
	*p1 = "hi";

make_shared函数

shared_ptr<int> p3 = make_shared<int>(42) //指向一个值为42的int的shared_ptr
auto p6 = make_shared<vector<string>>() //p6指向一个动态分配的空 vector<string>

shared_ptr的拷贝和赋值

每个shared_ptr都有一个关联计数器,称为引用计数:

计数器增加:

1、当拷贝一个shared_ptr时。

2、当用一个shared_ptr初始化另一个shared_ptr时

3、当shared_ptr作为参数传递给一个函数时,或作为函数返回时

计数器递减:

1、当给shared_ptr赋予一个新值

2、当shared_ptr被销毁(局部shared_ptr离开其作用域)

当shared_ptr计数器变为0,它会自动释放自己所管理的对象。

auto q = make_shared<int>();
auto r = make_shared<int>(42);
r = q;   //q指向对象计数器加1,r原来指向对象引用计数器减1,计数器为0,r原来指向对象自动释放

shared_ptr自动销毁所管理的对象,并释放所关联的内存

shared_ptr类通过析构函数销毁所管理的对象。

12.1.2 直接管理内存

使用new动态分配与初始化对象

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

默认初始化,内置类型对象值未定义。类类型对象使用默认构造函数初始化

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

直接初始化:

int *pi = new int(1024);

构造方式(圆括号)

string *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();

由初始化器推断要分配对象类型:

auto p1 = new auto(obj); //p指向一个与obj类型相同的对象,该对象用obj进行初始化

动态分配const对象

const int *pci = new const int(1024);

内存耗尽

int *p1 = new int; //如果分配失败,new抛出std::bad_alloc
int *p2 = new (nothrow) int ; //如果分配失败,new返回一个空指针

释放动态内存

delete p; //p必须指向一个动态分配的对象或一个空指针

delete表达式执行两个动作:销毁给定指针指向的对象,释放对应的内存。

指针值和delete

不能释放一块非new分配的内存,或将相同的指针值释放多次。

new和delete管理动态内存的三个问题:

1、忘记delete内存。

2、使用已经释放掉的对象。

3、同一块内存释放两次。

空悬指针

delete一个指针后,指针无效,但该指针仍然保存着,这就是空悬指针。

在delete之后将nullptr赋予指针。

12.1.3 shared_ptr和new结合使用

使用new返回的指针来初始化智能指针

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

不要混合使用普通指针和智能指针

void process(shared_ptr<int> ptr)
{
    //使用ptr
    //ptr离开作用域,被销毁
}
//正确
shared_ptr<int> p(new int(42));
process(p); //拷贝p会递增它的引用计数,在process中引用计数器为2
int i = *p;
//错误
int *x(new int(1024));
process(x); //不能减int*转换为一个shared_ptr<int>
process(shared_ptr<int>(x));//合法,当内存会被释放
int j = *x;//未定义,x是一个空悬指针

不要使用get初始化另一个智能指针或为智能指针赋值

shared_ptr<int> p(new int(42));
int *q = p.get();
{
    shared_ptr<int>(q); //未定义,两个独立的shared_ptr指向相同的内存
} //程序结束,q被销毁,指向的内存被释放
int foo = *p //未定义:p指向内存已经释放了

其他shared_ptr操作

p = new int(1024); //错误,不能将一个新的指针赋予shared_ptr
p.reset(new int(1024));

12.1.4 智能指针和异常

当发生异常时,直接管理内存时不会自动释放的。智能指针指向的内存却可以释放。

void f()
{
    shared_ptr<int> sp(new int(42));
    //出现异常,未被捕获
}  //函数结束时shared_ptr自动释放

void f()
{
    int *IP= new int(42);
    //出现异常,未被捕获
    delete ip; //内存不会被释放
}

使用自己的释放操作

在shared_ptr中定义删除器。

12.1.5 unique_ptr

与shared_ptr不同,某时刻一个unique_ptr只能指向一个给定对象。当unique_ptr被销毁时,它所指向的对象也被销毁。

初始化unique_ptr必须采用直接初始化的形式:

unique_ptr<int> p2(new int(42));

不支持普通拷贝和赋值

unique_ptr<string> p1(new string("abc"));
unique_ptr<string> p2(p1);  //错误
unique_ptr<string> p3;
p3 = p2; //错误

通过release或reset将指针所有权从一个unique_ptr转移到另一个unique。

unique_ptr<string> p2(p1.release()) //release将p1置为空,p1放弃指针控制权,返回指针
unique_ptr<string> p3(new string("def"));
//将所有权从p3转移到p2
p2.reset(p3.release());//reset释放了p2原来指向的内存。

p2.release(); //错误 p2不会释放内存,而且会丢失指针
auto p = p2.release(); //正确,但必须记得delete(p)

传递unique_ptr参数和返回unique_ptr

可以拷贝或赋值一个将要被销毁的unique_ptr。

unique_ptr<int> clone(int p){
    return unique_ptr<int>(new int(p));
}

weak_ptr

weak_ptr指向一个shared_ptr管理的对象,将weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。一旦指向对象的shared_ptr被销毁,对象就会被释放。

12.2 动态数组

12.2.1 new和数组

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

	auto p =  new string[5]{"a","b","c","d","e"};
    for(auto q = p;q < p+5; q++)
    {
        cout << *q << " ";
    }
    cout << endl;
    delete [] p; //释放动态数组

智能指针和动态数组

unique<int[]> up(new int[10]); //unique<T[]> u(p) u指向内置指针p所指向的动态分配的数组。
up.release();

不能使用点和箭头成员运算符,只能使用下标运算符。

for(size_t i = 0; i !=10;++i)
	up[i] = i;

使用shared_ptr管理动态数组

必须定义删除器。

12.2.2 allocator类

allocator

allocator<string> alloc;  //可以分配string的allocator对象
auto const p = alloc.allocate(n);   //分配n个未初始化的string

allocator分配未构造的内存

auto q = p;
alloc.construct(q++,10,'c');

销毁string

while(q != p)
	alloc.destory(--q);//元素销毁后,可以重新使用这部分内存保存其他string

释放内存

alloc.deallocate(p,n);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

硬码农二毛哥

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

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

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

打赏作者

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

抵扣说明:

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

余额充值