【C++】动态内存与智能指针

C++中 内存划分:

  • 静态内存:保存局部static对象、类static数据成员、以及定义在任何函数之外的变量;
  • 栈内存:保存定义在函数内的非static对象;
  • 自由空间(堆):存储动态分配的对象,当动态对象不再使用时,需要显示的销毁;

 程序使用动态内存的原因:

  • 不知道自己需要使用多少对象;
  • 不知道所需对象的准确类型;
  • 需要在多个对象间共享数据;

智能指针

智能指针的行为类似于常规指针,负责自动释放所指向的对象;智能指针也是模板,默认初始化的智能指针里面保存着一个空指针;

智能指针模板类:定义在memory头文件中

  • shared_ptr:允许多个指针指向同一个对象;
  • unique_ptr:独占所指的对象;
  • weak_ptr:是一种弱引用,指向shared_ptr所管理的对象; 

shared_ptr 和 unique_ptr 共有的一些操作:

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

p.get()    //返回p中保存的指针

swap(p, q)    //交换p和q中的指针
p.swap(q)

关于正确使用智能指针的一些规范:

  • 不使用相同的内置指针值初始化或reset多个智能指针。
  • 不delete get()返回的指针。
  • 不使用get()初始化或reset另一个智能指针。
  • 如果你使用get()返回的指针,记住当最后一个对应的智能指针销毁后,指针就会变的无效了。
  • 如果使用智能指针管理的资源不是new分配的内存,记住传递给它一个删除器。

shared_ptr

独有的一些重要的操作:

make_shared<T>(args)    //返回一个shared_ptr,指向动态分配的类型为T的对象,使用args初始化

shared_ptr<T>p(q)    //拷贝

p.unique()    //返回bool,判断是否有共享的指针数量

p.use_count()    //返回与p共享的智能指针数量,主要用于调试

shared_ptr进行拷贝之后都指向同一个对象,会有一个引用计数,一旦计数器变为0,就会调用析构函数,自动释放自己管理的对象;

保证shared_ptr在无用之后不再保留非常重要,其在无用之后仍然保留的一种可能情况是,将shared_ptr放在了一个容器中,然后重排了容器,从而不需要某些元素;如果将shared_ptr存放在一个容器中,而后不需要全部的元素而只需要用其中一部分,需要用eraser删除不需要的那些元素;


直接管理内存

C++使用 newdelete 分配和释放内存;

new

new无法为其分配的对象命名,而是返回一个指向该对象的指针:

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

//不指定初始化的值,则对象都会通过默认构造函数来初始化

分配const对象时:

const int *pci = new const int(1024);    //分配并初始化一个const int

一个动态分配的const对象一定要进行初始化。对于一个定义了默认构造函数的类可以隐式的初始化,其他的类型的对象必须显示初始化。

 delete

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

编译器不能分辨一个指针是静态还是动态分配的对象。编译器也不能分辨一个指针指向的的内存是否已经被释放了。

由内置指针管理的动态内存被显示的释放之前一直会存在。

关于空悬指针的问题:
当我们delete一个指针之后,指针值就变得无效了,但有时指针仍然保存着(已经释放了的)动态内存的地址。所以我们需要在指针离开其作用域之前释放掉它关联的内存。如果我们需要继续使用此指针,可以delete之后赋予nullptr

关于多个指针指向相同内存的问题:
delete其中一个指针后,其他的指针需要置空。

int *p(new int(42));    //p指向动态内存
auto q = p;    //p和q指向相同的内存
delete p;    //q和p均无效
p = nullptr;    //指出p不再绑定到任何对象

shared_ptr 和 new 的结合使用

接受指针参数的智能指针构造函数是explicit的,也就是只能通过直接初始化,不能拷贝初始化。不能将一个内置指针隐式转换为一个智能指针,必须使用直接初始化的形式。

shared_ptr<int> p1 = new int(11);    //错误
shared_ptr<int> p2(new int(42));    //正确

当使用shared_ptr绑定到一个普通指针时,我们就将内存的管理责任交给了这个shared_ptr,这样做了之后就不应该再使用内置指针来访问shared_ptr指向的内存了。

不要混合使用智能指针和内置指针,也不要使用get初始化另一个智能指针或为另一个智能指针赋值。get():返回智能指针管理对象的一个内置指针。


unique_ptr

与shared_ptr相似,需要将其绑定到一个new返回的指针上,初始化unique_ptr必须使用直接初始化的形式,与之不同的是它不支持拷贝,不支持赋值

unique_ptr 一些常用的操作:

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

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

u.reset(p)    //释放原来的,再指向p

weak_ptr

weak_ptr不控制所指向对象生存期的智能指针,将一个weak_ptr绑定到shared_ptr上不会改变shared_ptr的引用计数。

weak_ptr一些常用的操作:

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

由于对象可能不存在,我们不能使用weak_ptr直接访问对象,而必须调用lock。weak_ptr不能影响对象,但可以检查对象在不在。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值