C++14 智能指针unique_ptr、shared_ptr、weak_ptr
来源:互联网 发布:模拟基金交易软件 编辑:程序博客网 时间:2024/05/22 10:27
内存控制这一大毒瘤,几乎一直伴随着C/C++工程师。随着计算机技术的发展,在boost准标准库的推动下,C++11终于将unique_ptr、shared_ptr、weak_ptr这几类智能指针纳入C++中。当然,在这之前还有一种auto_ptr智能指针,不过由于它的设计存在较大问题(比如:auto_ptr与STL不兼容),现阶段已经很少能看到它的出现了。
目录:
- unique_ptr
- shared_ptr
- weak_ptr
智能指针实质是一个对象,行为表现的却像一个指针。
shared_ptr和unique_ptr之间的区别在于:shared_ptr是引用计数的智能指针,而unique_ptr不是。这意味着,可以有多个shared_ptr实例指向同一块动态分配的内存,当最后一个shared_ptr离开作用域时,才会释放这块内存。shared_ptr也是线程安全的。另一方面,unique_ptr意味着所有权。单个unique_ptr离开作用域时,会立即释放底层内存。
默认的智能指针应该是unique_ptr。只有需要共享资源时,才使用shared_ptr。
这两个智能指针都需要包含<memory>
头文件。
在开始本文之前,首先给出一个类。因为下文中,为了演示智能指针的使用方式,在较多时候都有用到这个类demo。
#include <memory>#include <utility> //std::move()class demo {public: demo() : uptr(std::make_unique<int[]>(10)){ printf("demo\n"); for (int i = 0; i < 10; ++i){ uptr[i] = i; } } ~demo(){ printf("~demo\n"); } void show(){ printf("%d\n", uptr[9]); }private: std::unique_ptr<int[]> uptr;};
unique_ptr
unique_ptr是唯一的,适用于存储动态分配的旧C风格的数组。auto关键字会自动识别指针类型,当与make_unique配合使用时,即表示unique_ptr智能指针。
void my_unique_ptr(){ auto uptr = std::make_unique<int[]>(10); uptr[5] = 17; printf("%d\n", uptr[5]);}
这里应该总是使用auto/make_unique写法。除非编译器不支持的情况下,可以这样写,
std::unique_ptr<int[]> uptr(new int[10]);//std::unique_ptr<int[]> uptr = new int[10];//error
注意,上文中,被注释的那种写法是不被接受的。再整理一下,unique_ptr可以有以下使用方式,
void my_unique_ptr2(){ auto uptr = std::make_unique<demo>(); uptr->show(); std::unique_ptr<demo> uptr2(new demo());///等效写法 uptr2->show();}
另外,需要说明的是,unique_ptr无法使用拷贝构造函数的,上文已经提到过了,这里再给出一个示例,
void my_unique_ptr3(){ auto uptr = std::make_unique<int>(42); printf("%d\n", *uptr);//42 ///std::unique_ptr<int> uptr1 = uptr; ///unique_ptr无拷贝构造函数 ///std::unique_ptr<int> uptr1(uptr); ///等效写法 std::unique_ptr<int> uptr2 = std::move(uptr); ///printf("%d\n",*uptr); ///error 所有权已交给uptr2 printf("%d\n", *uptr2);}
既然,无法使用拷贝构造函数,那么就无法直接使用赋值“=”来转移指针所有权。但是C++14设计者给开了另外一扇门:std::move。它被包含在<utility>
头文件中。
shared_ptr
shared_ptr用法与unique_ptr类似。如果编译器支持,你应该总是使用auto/make_shared的写法,它比直接创建shared_ptr更高效。
void my_shared_ptr(){ ///auto sptr = std::make_shared<int[]>(10); //error ///sptr[6] = 20; auto sptr = std::make_shared<demo>(); sptr->show();}
上文中已经提到了,智能指针家族中,unique_ptr是唯一可以适用于旧C风格数组的指针,shared_ptr等其他智能指针不能。
shared_ptr除了用于管理纯粹的内存之外还可以用于其他的目的,比如管理FILE、SOCKET等,极大的增加了编程的方便性。
void auto_run_fun(FILE* f){ printf("auto running.\n"); fclose(f);}void my_shared_ptr2(){ FILE* f = fopen("data.txt","w"); std::shared_ptr<FILE> file_ptr(f, auto_run_fun);}
由于shared_ptr是引用计数的,这里需要极为注意的一点是:糟糕!只调用一次构造函数,却调用了两次析构函数。
正确的使用方式应该是使用make_shared和拷贝构造函数建立副本。范例如下,
void my_shared_ptr3(){ /*demo* d = new demo(); std::shared_ptr<demo> sptr1(d); std::shared_ptr<demo> sptr2(d);//~demo() error */ auto sptr3 = std::make_shared<demo>(); std::shared_ptr<demo> sptr4(sptr3); ///shared_ptr拷贝构造函数}
shared_ptr引用计数,完全可以返回一个子函数的指针。在以往的认知中,子函数中的栈空间上的内存是无法返回的,而子函数中堆空间上的内存是可以返回的(同时,还必须注意手动释放它,否则必然内存泄漏)。
std::shared_ptr<demo> my_shared_ptr4(){ auto sptr = std::make_shared<demo>(); return sptr;}
那么,对于以上代码的返回值,下文中这样子使用它,也是非常正确的。
my_shared_ptr4()->show();
智能指针,完全继承了JAVA和C#中内存托管的风格,而且智能指针在很多情况下完全可以具体推算出:它会在何时被释放。
weak_ptr
weak_ptr是shared_ptr的黄金伙伴。从上文知道shared_ptr与shared_ptr之间,每拷贝一次,引用计数就会+1,而如果使用weak_ptr则不会出现这个现象。
如果将一个shared_ptr指针赋值给weak_ptr指针,对shared_ptr指针本身不会造成任何影响。对于weak_ptr指针来说,却可以通过一些方法来探测被赋值过来的shared_ptr指针的有效性,同时weak_ptr指针也可以间接操纵shared_ptr指针。以下主要介绍两个方法:
- lock() ,weak_ptr指针调用lock()方法会获得一个返回值:shared_ptr。而这个返回值就是被赋值过来的shared_ptr指针,那么指针都获得了,当然可以操纵它。
- expired() ,该方法主要用来探测shared_ptr指针的有效性。shared_ptr一旦被释放,指针就会被置为nullptr。
///weak_ptr -> shared_ptrvoid my_weak_ptr(){ std::weak_ptr<demo> wptr; { auto sptr = std::make_shared<demo>(); wptr = sptr; auto sptr2 = wptr.lock(); if (!wptr.expired()){///等价于sptr2 != nullptr printf("shared_ptr ok\n"); sptr2->show(); } } if (wptr.expired()){ printf("shared_ptr deleted\n"); }}
以上代码中,之所以要加个大括号{}在文中,主要是:为了利用变量的作用域原理。让shared_ptr指针离开{}作用域后,立即被释放。
本文源码:auto_ptr
参考文献:
Marc, Gregoire. C++高级编程(第3版)[M]. 北京:清华大学出版社, 2015. 630-636
- 【C++】智能指针auto_ptr/unique_ptr/shared_ptr/weak_ptr!!!
- C++14 智能指针unique_ptr、shared_ptr、weak_ptr
- C++ 智能指针 shared_ptr unique_ptr weak_ptr
- C++11 智能指针 unique_ptr shared_ptr weak_ptr
- 智能指针shared_ptr、weak_ptr、unique_ptr总结
- C++智能指针 shared_ptr,unique_ptr和weak_ptr
- C++11新特性之智能指针(shared_ptr/unique_ptr/weak_ptr)
- auto_ptr, unique_ptr, shared_ptr and weak_ptr智能指针讲解
- C++11 智能指针std::shared_ptr/std::unique_ptr/std::weak_ptr
- 智能指针--shared_ptr&&weak_ptr
- stl中auto_ptr,unique_ptr,shared_ptr,weak_ptr四种智能指针使用总结
- C++中的智能指针——auto_ptr, unique_ptr, shared_ptr和weak_ptr
- 智能指针---shared_ptr和weak_ptr
- Boost智能指针shared_ptr、weak_ptr
- 智能指针--scoped_ptr shared_ptr weak_ptr
- shared_ptr,weak_ptr,unique_ptr
- C++:智能指针-TR1的shared_ptr和weak_ptr使用介绍
- C++:智能指针-TR1的shared_ptr和weak_ptr使用介绍
- CodeForces
- 四轴PID讲解
- ARKit demo应用程序有什么?十二居做家装AR领头羊
- ABP理论学习之事件总线和领域事件
- 深度学习优化方法总结
- C++14 智能指针unique_ptr、shared_ptr、weak_ptr
- Codeforces791 C. Bear and Different Names
- v-for 指令
- 0-1背包问题
- ARouter源码解析01-编译生成文件
- 云平台建设学习6
- 驱动程序调试常用方法
- Python学习三——列表
- 面试题 44: 扑克牌的顺子