经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
<一>智能指针基础
来源:cnblogs  作者:Hello_Bugs  时间:2022/12/2 15:22:23  对本文有异议

代码1

  1. int main(){
  2. //裸指针,手动开辟,需要自己释放,如果忘记了或者因为
  3. //程序逻辑导致p没有释放,那么就会导致内存泄漏
  4. int *p=new int(10);
  5. if(***){
  6. retur -1;
  7. }
  8. delete p;
  9. return 0;
  10. }

有没有什么办法帮我们管理指针,确保资源释放?
智能指针
利用栈上的对象出作用域时自动析构的特征,来做到资源的自动释放
问题:是否可以在堆上创建裸指针?语法上没有问题,但是我们正式希望
栈上对象出作用域能自动析构的特征来达到自动管理指针的目的,如果
将智能指针创建在堆上,那又和原来的裸指针使用遇到的问题是一样的了
需要手动delete

代码2

  1. #include <iostream>
  2. using namespace std;
  3. template<typename T>
  4. class MySmartPtr1 {
  5. public:
  6. MySmartPtr1(T * ptr=nullptr) : _mptr(ptr) { }
  7. ~MySmartPtr1() {
  8. delete _mptr;
  9. _mptr = nullptr;
  10. }
  11. T & operator*() { return *_mptr; }//返回的 是 & , 需要修改值
  12. T * operator->() { return _mptr; }
  13. private:
  14. T * _mptr;
  15. };
  16. int main() {
  17. MySmartPtr1<int> ptr(new int(10));
  18. *ptr= 200;
  19. return 0;
  20. }

代码2的问题

  1. int main() {
  2. MySmartPtr1<int> ptr(new int(10));
  3. //使用ptr 拷贝构造ptr2,默认的拷贝构造方式是值拷贝,所以底层
  4. //_mptr指针 指向的是同一块内存,那么ptr2 和ptr析构的时候就会有问题了,两次析构同一片内存
  5. MySmartPtr1<int> ptr2(ptr);
  6. *mptr = 200;
  7. return 0;
  8. }

如何解决呢?
1:不带引用计数的智能指针
auto_ptr C++库提供
C++11 新标准
scoped_ptr
unique_ptr

代码 关于 auto_ptr

  1. int main() {
  2. auto_ptr<int> ptr1(new int(100));
  3. auto_ptr<int> ptr2(ptr1);
  4. *ptr2 = 200;
  5. cout<<*ptr1<<endl;//执行报错,原因见下图
  6. return 0;
  7. }

现在不推荐使用auto_ptr
容器中推荐用auto_ptr吗? vector<auto_ptr> v1; v2(v1); 容器的拷贝构造和容器的赋值容易引起容器元素的拷贝构造和赋值,而auto_ptr的拷贝构造会将原来管理的底层资源(指针)置空

代码关于 scoped_ptr

  1. int main() {
  2. scope_ptr的处理方式
  3. scope_ptr<int>(const scope_ptr<int> & src)=delete;//通过直接和谐掉这两个方法
  4. scope_ptr<int> & operator=(const scope_ptr<int> & src))=delete;//通过直接和谐掉这两个方法
  5. return 0;
  6. }
  7. 所以scoped_ptr使用的也很少

代码关于 unique_ptr

  1. int main() {
  2. unique_ptr的处理方式
  3. unique_ptr<int>(const unique_ptr<int> & src)=delete;//通过直接和谐掉这两个方法
  4. unique_ptr<int> & operator=(const unique_ptr<int> & src))=delete;//通过直接和谐掉这两个方法
  5. unique_ptr<int> ptr1(new int(100));
  6. unique_ptr<int> ptr2(ptr1);//编译报错,尝试使用已经删除的函数, 要改成如下!!!
  7. unique_ptr<int> ptr1(new int(100));
  8. unique_ptr<int> ptr2(std::move(ptr1));//编译OK,为什么可以呢?因为unique_ptr提供了右值引用的拷贝构造和右值引用的赋值函数,如下
  9. unique_ptr<int>(const unique_ptr<int> && src){};
  10. unique_ptr<int> & operator=(const unique_ptr<int> && src)){};
  11. return 0;
  12. }
  13. //推荐使用

2:带引用计数的智能指针(share_ptr,weak_ptr)

带引用计数的好处:多个智能指针可以管理同一个资源
带引用计数:给每一个对象资源,匹配一个引用计数,
智能指针引用一个资源的时候,给这个资源引用计数加1
当这个智能指针出作用域不再使用资源的时候,给这个资源引用计数-1,当引用计数不为0的时候,还不能析构这个资源,
当引用计数为0的时候,说明已经没有外部资源使用这个资源了,那么就可以析构这个资源了

代码3 简单实现share_ptr

  1. #include <iostream>
  2. using namespace std;
  3. template<typename T>
  4. class RefCount {
  5. public:
  6. RefCount(T * pSrc = nullptr, int refCount = 0):_pSrc(pSrc),_refCount(refCount) {
  7. }
  8. void addCount() { this->_refCount++; }
  9. void deleltCount() { --this->_refCount; }
  10. int refCount() { return this->_refCount; }
  11. private:
  12. T * _pSrc;
  13. int _refCount = 0;
  14. };
  15. template<typename T>
  16. class MySmartPtr2 {
  17. public:
  18. //新创建的智能指针,默认计数器为1
  19. MySmartPtr2<T> (T * mptr=nullptr): _mptr(mptr){
  20. _pRef = new RefCount<T>(_mptr,1);
  21. }
  22. //拷贝构造
  23. MySmartPtr2<T>(const MySmartPtr2<T> & _rval) {
  24. //两个智能指针指向相同的资源
  25. this->_mptr = _rval._mptr;
  26. this->_pRef = _rval._pRef;
  27. this->_pRef->addCount();
  28. }
  29. //赋值重载
  30. MySmartPtr2<T> & operator=(const MySmartPtr2<T> & _rval) {
  31. if (this == &_rval) { retur *this; }
  32. else {
  33. this->_pRef->deleltCount();
  34. int currentCount = this->_pRef->refCount();
  35. if (currentCount == 0) {
  36. delete this->_mptr;//销毁指向的资源
  37. this->_mptr = nullptr;
  38. delete _pRef;
  39. _rPef = nullptr;
  40. }
  41. this->_pRef = _rval._pRef;
  42. this->_mptr = _rval._mptr;
  43. this->_pRef->addCount();
  44. return *this;
  45. }
  46. }
  47. ~MySmartPtr2<T>() {
  48. this->_pRef->deleltCount();
  49. int currentCount = this->_pRef->refCount();
  50. if (currentCount == 0) {
  51. delete this->_mptr;//销毁指向的资源
  52. this->_mptr = nullptr;
  53. delete _pRef;
  54. _pRef = nullptr;
  55. }
  56. }
  57. int getRefCount() { return this->_pRef->refCount(); }
  58. private:
  59. T * _mptr;
  60. RefCount<T> * _pRef;
  61. };
  62. int main() {
  63. MySmartPtr2<int> ms1(new int(100)) ;
  64. {
  65. MySmartPtr2<int> ms2(ms1);
  66. cout << "RefCount=" << ms1.getRefCount() << endl;
  67. MySmartPtr2<int> ms3(ms1);
  68. cout << "RefCount=" << ms1.getRefCount() << endl;
  69. }
  70. cout << "RefCount=" << ms1.getRefCount() << endl;
  71. system("pause");
  72. return 0;
  73. }

share_ptr: 强智能指针,可以改变资源的引用计数
weak_ptr: 弱智能指针,不会改变资源的引用计数

强智能指针:循环引用(交叉引用)是什么问题?什么结果?怎么解决?

交叉引用代码

  1. class A{
  2. pubic:
  3. A(){cout<<"A()"<<endl;}
  4. ~A(){cou<<"~A()"<<endl;}
  5. share_ptr<B> _ptrb;
  6. }
  7. class B{
  8. pubic:
  9. B(){cout<<"B()"<<endl;}
  10. ~B(){cou<<"~B()"<<endl;}
  11. share_ptr<A> _ptrb;
  12. }
  13. int main(){
  14. share_ptr<A> pa(new A());
  15. share_ptr<B> pb(new B());
  16. pa->_ptrb=pb;
  17. pb->_ptra=pa;
  18. cout<<pa.use_count()<<endl;// 2
  19. cout<<pb.use_count()<<endl;// 2
  20. }

上面代码造成new出来的资源无法释放!!资源泄漏问题

解决:
定义对象的时候,用强智能指针,引用对象的地方用弱智能指针

  1. class A{
  2. pubic:
  3. A(){cout<<"A()"<<endl;}
  4. ~A(){cou<<"~A()"<<endl;}
  5. void testA(){
  6. cout<<"A testA() Function"<<endl;
  7. }
  8. weak_ptr<B> _ptrb;
  9. }
  10. class B{
  11. pubic:
  12. B(){cout<<"B()"<<endl;}
  13. ~B(){cou<<"~B()"<<endl;}
  14. void function(){
  15. share_ptr<A> _tp=_ptrb.lock();//提升方法
  16. if(_tp!=nullptr){
  17. _tp->testA();
  18. }
  19. }
  20. weak_ptr<A> _ptrb; //weak_ptr 弱智能指针,不会改变引用计数
  21. }
  22. int main(){
  23. share_ptr<A> pa(new A());
  24. share_ptr<B> pb(new B());
  25. pa->_ptrb=pb;
  26. pb->_ptra=pa;
  27. pb.function();
  28. cout<<pa.use_count()<<endl;// 2
  29. cout<<pb.use_count()<<endl;// 2
  30. }

share_ptr 和 weak_ptr 是线程安全的.

原文链接:https://www.cnblogs.com/erichome/p/16943460.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号