谈谈智能指针
2016-05-05 09:48
267 查看
使用new和delete来管理动态内存常出的一些错误:
1.忘记delete,即导致了“内存泄漏”,
2.野指针。在对象已经被释放掉之后,(这里注意,此时的指针成为了悬垂指针,即指向曾经存在的对象,但该对象已经不再存在。结果未定义,而且难以检测。)这时候我们再次使用,会产生使用非法内存的指针。
不过如果我们需要保留指针,可以在delete以后将nullptr赋予指针,这样指针就不指向任何对象了,如下代码:
题外话:在测试这个问题的时候,我输出了下q的值发现还是42,并且没有报错,后来在delete p之后,我又给*p = 19;这个时候 p ,q的值在输出的时候都是19,也没有报错。这个代码其实根本就是错误的了,因为p,q已经没有有效的内存空间了。这里是释放了内存,但指针的值不变,指向的内存不会清0,指向的这片内存区域是待分配的,如果没有被其他数据覆盖的话,你就能幸运得输出这主要原因是你分配的内存小,没有继续分配,被占用的概率小所致。我用的xcode,换到VS下就正常报错了,是因为VS为了从编译器的角度上解决缓冲区溢出等问题,加上的这种功能,C++标准里面没有这么要求,所有xcode和gcc是不会检查的。所以在这里
建议大家写纯C++代码的时候用vs。
3.重复delete,就会使自由空间遭到破坏
智能指针和普通指针的区别在于智能指针实际上是对普通指针加了一层封装机制,这样的一层封装机制的目的是为了使得智能指针可以方便的管理一个对象的生命期。
在C++中,我们知道,如果使用普通指针来创建一个指向某个对象的指针,那么在使用完这个对象之后我们需要自己删除它,例如:
很多材料上都会指出说如果程序员忘记在调用完temp_ptr之后删除temp_ptr,那么会造成一个悬挂指针(dangling pointer),也就是说这个指针现在指向的内存区域其内容程序员无法把握和控制,也可能非常容易造成内存泄漏。
可是事实上,不止是“忘记”,在上述的这一段程序中,如果foo()在运行时抛出异常,那么temp_ptr所指向的对象仍然不会被安全删除。
在这个时候,智能指针的出现实际上就是为了可以方便的控制对象的生命期,在智能指针中,一个对象什么时候和在什么条件下要被析构或者是删除是受智能指针本身决定的,用户并不需要管理。
所以就出现了智能指针这种东西:
智能指针(英语:Smart
pointer)是一种抽象的数据类型。在程序设计中,它通常是经由类模板(class
template)来实做,借由模板(template)来达成泛型,通常借由类(class)的析构函数来达成自动释放指针所指向的内存或对象。(维基百科)
C++ 有三种智能指针auto_ptr、unique_ptr 和shared_ptr,以及weak_ptr.
C++11中提供了
C++11新增了move语义,相比copy语义,它能更好的实现值传递.
uniqu_ptr的拷贝构造函数和赋值运算符都声明为deleted,也就是说它不能被拷贝,只能通过
也就是如果是右值的话就可以给其他对象赋值,其他存在时间长的对象都不可以进行拷贝,只能使用c11 move语义实现内存所有权的传递
另外对于shared_ptr和weak_ptr
weak_ptr是一个弱引用,只引用,不计数。如果一块内存被shared_ptr和weak_ptr同时引用,当所有shared_ptr析构了之后,不管还有没有weak_ptr引用该内存,内存也会被释放。所以
参考:
1:@知乎胡昊 链接:https://www.zhihu.com/question/20368881/answer/14918675
2: 维基百科:https://zh.wikipedia.org/wiki/%E6%99%BA%E8%83%BD%E6%8C%87%E9%92%88
1.忘记delete,即导致了“内存泄漏”,
2.野指针。在对象已经被释放掉之后,(这里注意,此时的指针成为了悬垂指针,即指向曾经存在的对象,但该对象已经不再存在。结果未定义,而且难以检测。)这时候我们再次使用,会产生使用非法内存的指针。
不过如果我们需要保留指针,可以在delete以后将nullptr赋予指针,这样指针就不指向任何对象了,如下代码:
auto p(new auto 42); auto q = p; delete p; p = nullptr;
题外话:在测试这个问题的时候,我输出了下q的值发现还是42,并且没有报错,后来在delete p之后,我又给*p = 19;这个时候 p ,q的值在输出的时候都是19,也没有报错。这个代码其实根本就是错误的了,因为p,q已经没有有效的内存空间了。这里是释放了内存,但指针的值不变,指向的内存不会清0,指向的这片内存区域是待分配的,如果没有被其他数据覆盖的话,你就能幸运得输出这主要原因是你分配的内存小,没有继续分配,被占用的概率小所致。我用的xcode,换到VS下就正常报错了,是因为VS为了从编译器的角度上解决缓冲区溢出等问题,加上的这种功能,C++标准里面没有这么要求,所有xcode和gcc是不会检查的。所以在这里
建议大家写纯C++代码的时候用vs。
3.重复delete,就会使自由空间遭到破坏
智能指针和普通指针的区别在于智能指针实际上是对普通指针加了一层封装机制,这样的一层封装机制的目的是为了使得智能指针可以方便的管理一个对象的生命期。
在C++中,我们知道,如果使用普通指针来创建一个指向某个对象的指针,那么在使用完这个对象之后我们需要自己删除它,例如:
ObjectType* temp_ptr = new ObjectType(); temp_ptr->foo(); delete temp_ptr;
很多材料上都会指出说如果程序员忘记在调用完temp_ptr之后删除temp_ptr,那么会造成一个悬挂指针(dangling pointer),也就是说这个指针现在指向的内存区域其内容程序员无法把握和控制,也可能非常容易造成内存泄漏。
可是事实上,不止是“忘记”,在上述的这一段程序中,如果foo()在运行时抛出异常,那么temp_ptr所指向的对象仍然不会被安全删除。
在这个时候,智能指针的出现实际上就是为了可以方便的控制对象的生命期,在智能指针中,一个对象什么时候和在什么条件下要被析构或者是删除是受智能指针本身决定的,用户并不需要管理。
所以就出现了智能指针这种东西:
智能指针(英语:Smart
pointer)是一种抽象的数据类型。在程序设计中,它通常是经由类模板(class
template)来实做,借由模板(template)来达成泛型,通常借由类(class)的析构函数来达成自动释放指针所指向的内存或对象。(维基百科)
C++ 有三种智能指针auto_ptr、unique_ptr 和shared_ptr,以及weak_ptr.
对于unique_ptr
C++11中提供了std::unique_ptr,定义在
<memory>头文件中。
C++11新增了move语义,相比copy语义,它能更好的实现值传递.
std::auto_ptr使用的是copy语义,为了向前兼容,C++11没有修改std::auto_ptr,而是引入了新的使用move语义的
std::unique_ptr.
uniqu_ptr的拷贝构造函数和赋值运算符都声明为deleted,也就是说它不能被拷贝,只能通过
std::move来转递它所指向的内存的所有权。
也就是如果是右值的话就可以给其他对象赋值,其他存在时间长的对象都不可以进行拷贝,只能使用c11 move语义实现内存所有权的传递
另外对于shared_ptr和weak_ptr
std::shared_ptr使用引用计数,所以有循环计数的问题。为了打破循环,可以使用
std::weak_ptr.顾名思义,
weak_ptr是一个弱引用,只引用,不计数。如果一块内存被shared_ptr和weak_ptr同时引用,当所有shared_ptr析构了之后,不管还有没有weak_ptr引用该内存,内存也会被释放。所以
weak_ptr不保证它指向的内存一定是有效的,在使用之前需要检查。
参考:
1:@知乎胡昊 链接:https://www.zhihu.com/question/20368881/answer/14918675
2: 维基百科:https://zh.wikipedia.org/wiki/%E6%99%BA%E8%83%BD%E6%8C%87%E9%92%88
相关文章推荐
- 实战Java虚拟机图片
- HDU 1024 Max Sum Plus Plus(DP+滚动数组)
- 认识Jenkins
- Android四大组件之Broadcast
- Unity3d OnApplicationPause与OnApplicationFocus
- 12个优化Unity/GearVR应用的小技巧
- Struts2文件上传--多文件上传(插件uploadify)
- C#代码
- shell编程
- Android软键盘隐藏,遮挡EidtText解决办法
- DX和Shader model/windows关系
- Ubuntu, Mac 下 Web 开发环境搭建:node.js, golang 与 revel 配置安装
- C/C++中声明与定义
- NSString拼接
- 《VR入门系列教程》之6---VR硬件介绍及DK1
- C++实验-5
- c++第五次作业
- C++实验5——数组分离
- PHP命名空间带来的干扰
- uva 10935 throwing cards away <queue>