C++动态内存

动态内存

  • 动态分配的对象的生存期与其在哪创建无关,只有当显式地被释放时,对象才会被销毁

动态内存和智能指针

  • new:在动态内存中为对象分配空间并返回一个指向该对象的指针
  • delete接受一个动态对象的指针,销毁该对象,并释放与之关联的内存

shared_ptr类

  • 为模板,当创建一个智能指针时,必须提供额外的信息——指针可以指向的类型
  • 允许多个指针指向同一个对象
shared_ptr<string>p1;//可以指向string
shared_ptr<list<int>>p2;//可以指向int的list
  • 默认初始化的智能指针中保存着一个空指针

  • shared_ptr和unique_ptr都支持的操作

shared_ptr<T>sp;
unique_ptr<T>up;
//空智能指针,可以指向类型为T的对象

p;
//将p用作一个条件判断,若p指向一个对象,则为true

*p;
//解引用p,获得它指向的对象

p->mem;
(*p).mem;

p.get();
//返回p中保存的指针。若智能指针释放了其对象,返回的指针所指向的对象也就小时了

swap(p,q);
p.swap(q);
//交换p,q中的指针
  • shared_ptr独有的操作
make_shared<T>(args);
//返回一个shared_ptr,指向一个动态分配的类型为T的对象,使用args初始化此对象

shared_ptr<T>p(q);
//p是shared_ptr q的拷贝,此操作会递增q中的计数器,q中的指针必须能转换为T*

p=q;
//p和q都是shared_ptr,所保存的指针必须能相互转换,此操作会递减p的引用计数,递增q的引用计数,若p的引用计数变为0,则将其管理的原内存释放

p.unique();
//若p.use_count()为1,返回true,否则返回false

p.use_count();
//返回与p共享对象的智能指针数量,可能很慢,主要用于调试
make_shared函数
  • 最安全的分配和使用动态内存的函数,在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr
  • 头文件memory
shared_ptr<int>p3=make_shared<int>(42);
//指向一个值为42的int的shared_ptr
shared_ptr<string>p4=make_shared<string>(10,'9');
//指向一个9999999999的string
shared_ptr<int>p5=make_shared<int>();
//指向一个值初始化的int,值为0
auto p6=make_shared<vector<string>>();
shared_ptr的拷贝和复制
  • 当进行拷贝或复制操作时,每个shared_ptr都会记录有多少个其他shared_ptr指向相同的对象
auto p = make_shared<int>(42);//p指向的对象只有p一个引用者
auto q(p);//p和q都指向相同对象,此对象有两个引用者
  • 引用计数:每个shared_ptr都有一个关联的计数器
  • 当给shared_ptr赋予一个新值或是shared_ptr被销毁时,计数器就会递减,一旦一个shared_ptr的计数器变为0就会自动释放其管理的对象
auto r = make_shared<int>(42);
r = q;
//给r赋值,令其指向另一个地址,递增q指向的对象的引用计数,递减r原来指向的对象的引用计数,r原来指向的对象已没有引用者,会自动释放
shared_ptr会自动释放相关联的内存
//factory返回一个shared_ptr,指向一个动态分配的对象
shared_ptr<Foo> factory(T arg){
    return make_shared<Foo>(arg);
}

//将factory返回的shared_ptr保存在局部变量中
void use_factory(T arg){
    shared_ptr<Foo>p=factory(arg);
}
//当p被销毁时,将递减其引用计数并检查是否为0,若为0则释放其至西安给定内存

//若将shared_ptr存放在一个容器中,而后不需要全部元素,只使用其中一部分,需记得用erase删除不再需要的元素

直接管理内存

使用new动态分配和初始化对象
string *ps = new string;//初始化为空的string
int *pi = new int;//pi指向一个未初始化的int
int *pi = new int(1024);
string *ps = new string(10,'9');
int *pi = new int();
auto p1 = new auto(obj);//p指向一个与obj类型相同的对象,该对象用obj初始化组
//auto p2 = new auto{a,b,c};//括号中只能由单个初始化器
动态分配的const对象
const int *pci = new const int(1024);
//new返回的指针式一个指向const的指针
内存耗尽
  • 若new不能分配所要求的内存空间,会抛出一个类型为bad_alloc的异常,可以使用new的方式来阻止器抛出异常
  • 头文件new
int *p1 = new int;//若分配失败,new抛出std::bad_alloc
int *p2 = new(nothrow) int;//若分配失败,new返回一个空指针(定位new)
释放动态内存delete
delete p1;//p1为空悬指针,指向一块曾经保存数据对象但现在已经无效的内存的指针
p1=nullptr;//重置指针

shared_ptr和new结合使用

//使用new返回的指针初始化智能指针
shared_ptr<double>p1;
shared_ptr<int>p2(new int(42));

//接受指针参数的智能指针构造函数时explicit,因此不能将一个内置指针隐式转换为一个智能指针,必须使用直接初始化形式
//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));
}
  • 定义和改变shared_ptr的方法
shared_ptr<T>p(q);
//p管理内存指针q所指向的对象,q必须指向new分配的内存,且能够转换为T*类型

shared_ptr<T>p(u);
//p从unique_ptr u那里接管了对象的所有权,将u置为空

shared_ptr<T>p(q,d);
//p接管了内置指针q所指向的对象的所有权,q必须能转换为T*类型,p将使用可调用对象d代替delete

shared_ptr<T>p(p2,d);
//p时shared_ptr p2的拷贝,唯一的区别时p将用可调用对象d来代替delete

p.reset();
p.reset(q);
p.reset(q,d);
//若p时唯一指向器对象的shared_ptr,reset会释放此对象。若传递了可选的参数内置指针q,会令p指向q,否则会将p置为空,若还传递了参数d,将会调用d而不是delete来释放q
  • 若使用智能指针,即使程序块过早结束,也能确保在内存不再需要时将其释放

unique_ptr

  • 某个时刻只能有一个unique_ptr指向一个给定对象,当unique_ptr被销毁时,其指向对象也被销毁
  • 定义unique_ptr时,需要将其绑定到一个new返回的指针上,初始化必须采用直接初始化形式
unique_ptr<double>p1;
unique_ptr<int>p2(new int(42));
unique_ptr<string>p1(new string("dd"));
//unique_ptr<string>p2(p1);
unique_ptr<string>p3;
//p3=p1;
  • unique_ptr操作
unique_ptr<T>u1;
unique_ptr<T,D>u2;
//空unique_ptr,可以指向类型为T的对象,u1会使用delete来释放其指针,u2会使用一个类型为D的可调用对象来释放其指针

unique_ptr<T,D>u(d);
//空unique_ptr,指向类型为T的对象,用类型为D的对象d代替delete

u = nullptr;
//释放u指向的对象,将u置为空

u.release();
//u放弃对指针的控制权,返回指针,并将u置为空

u.reset();
//释放u指向对象

u.reset(q);
u.reset(nullptr);
//如果提供了内置指针q,令u指向这个对象,否则将u置为空
传递unique_ptr参数和返回unique_ptr
  • 可以拷贝或赋值一个将要被销毁的unique_ptr
unique_ptr<int>clone(int p){
    return unique_ptr<int>(new int(p));
}

unique_ptr<int> clone(int p){
    unique_ptr<int>ret(new int(p));
    return ret;
}
向unique_ptr传递删除器
//p指向一个类型为objT的对象,并使用一个类型为delT的对象释放objT对象
//会调用一个名为fcn的delT类型对象
unique_ptr<objT,delT>p(new objT,fcn);

weak_ptr

  • 一种不控制所指向对象生存期的智能指针,指向有一个shared_ptr管理的对象
  • 将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用次数,一旦最后一个指向对象的shared_ptr被销毁,对象就会被释放
weak_ptr<T>w;
//空weak_ptr可以指向类型为T的对象

weak_ptr<T>(sp);
//与shared_ptr sp指向相同对象的weak_ptr,T必须能转换为sp指向的类型

w=p;
//p可以时一个shared_ptr或一个weak_ptr,赋值后w与p共享对象

w.reset();
//将w置为空

w.use_count();
//与w共享对象的shared_ptr的数量

w.expired();
//若w.use_count()为0,返回true,否则返回false

w.lock();
//如果expired为true,返回一个空shared_ptr,否则返回一个指向w的对象的shared_ptr

动态数组

new和数组

初始化动态分配对象的数组
int *pia = new int[10];
int *pia2 = new int[10]();
string *psa = new string[10];
string *psa2 = new string[10]();
int *pia = new int[10]{0,1,2,3,4,5,6,7,8,9};
释放动态数组
delete []pa;

allocator类

  • 头文件memory
allocator<string>alloc;//可以分配string的allocator对象
auto const p = alloc.allocator(n);//分配n个未初始化的string
  • 标准库allocator类与及算法
allocator<T>a;
//定义一个名为a的allocator对象,可以为类型T的对象分配内存

a.allocate(n);
//分配一段原始的、未构造的内存,保存n个类型为T的对象

a.deallocate(p,n);
//释放从T*指针p中地址开始的内存,这块内存保存了n个类型为T的对象,p必须时一个先前有allocate返回的指针,且n必须时p创建时所要求的大小,在调用deallocate之前,用户必须对每个在这块内存中创建的对象调用destroy

a.construct(p,args);
//p必须时一个类型为T*的指针,指向一块原始内存,arg被传递给类型为T的构造函数,用来在p指向的内存中构造一个对象

a.destroy(p);
//p为T*类型的指针,此算法对p指向的对象指向析构函数
allocator分配未构造的内存
  • construct成员函数接受一个指针和零个或多个额外参数,在给定位置构造一个原始,额外参数用来初始化构造的对象
auto q=p;//q指向最后构造的元素之后的位置
alloc.construct(q++);//*q为空字符串
alloc.construct(q++,10,'c');
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值