c++——智能指针学习(unique_ptr)
1.为什么会有unique_ptr?
动态内存忘记delete,导致内存泄漏。比如:
1 p = new (); 2 if(...) 3 { 4 return ; 5 } 6 delete p;
因此我们需要一种方式来解决这个问题,不管我们怎么折腾,能够避免内存不释放的问题。
于是我们引入了auto_ptr,但是auto_ptr相对来说有以下缺点,目前已经停用了。
缺点1:
缺点2:
auto_ptr的进化版unique_ptr就被引入进来。
2.unique_ptr的特点。
unique_ptr继承了auto_ptr的部分优点,对缺点进行改进。
unique_ptr 是一个独享所有权的智能指针,它提供了严格意义上的所有权,包括:
特点1 拥有它指向的对象
特点2 无法进行复制构造,无法进行复制赋值操作。即无法使两个unique_ptr指向同一个对象。但是可以进行移动构造和移动赋值操作
特点3 保存指向某个对象的指针,当它本身被删除释放的时候,会使用给定的删除器释放它指向的对象
这基本就满足我们某些场景下的需求了。
3.unique_ptr的使用
看代码
1 #include<iostream> 2 #include<memory> 3 class Mars 4 { 5 public: 6 ~Mars () 7 { 8 std::cout<<this<<"~Mars"<<std::endl; 9 } 10 void prin() 11 { 12 std::cout<<this<<",I am Mars"<<std::endl; 13 } 14 }; 15 16 int main() 17 { 18 { 19 Mars* mars = new Mars; 20 std::unique_ptr<Mars> pMars(mars); 21 std::cout << "pMars->prin: "; 22 pMars->prin(); 23 std::cout << "pMars.get()->prin: "; 24 pMars.get()->prin(); 25 std::cout << "(*pMars).prin: "; 26 (*pMars).prin(); 27 28 std::cout << "pMars:" << pMars.get() <<std::endl; 29 pMars.reset(new Mars); 30 std::cout << "pMars.reset.prin: "; 31 pMars->prin(); 32 33 std::unique_ptr<Mars> pMars2; 34 pMars2 = std::move(pMars); 35 std::cout << "pMars2.move.prin: "; 36 std::cout << "pMars2:" << pMars2.get() << std::endl; 37 pMars2->prin(); 38 } 39 40 system("pause"); 41 return 0; 42 }
4.unique_ptr的官方文档
官方文档:
std::unique_ptr
是通过指针占有并管理另一对象,并在 unique_ptr
离开作用域时释放该对象的智能指针。
在下列两者之一发生时用关联的删除器释放对象:
销毁了管理的 unique_ptr
对象
通过 operator= 或 reset() 赋值另一指针给管理的 unique_ptr
对象。
通过调用 get_deleter()(ptr) ,用潜在为用户提供的删除器释放对象。默认删除器用 delete 运算符,它销毁对象并解分配内存。
unique_ptr
亦可以不占有对象,该情况下称它为空 (empty)。
std::unique_ptr
有两个版本:
类满足可移动构造 (MoveConstructible) 和可移动赋值 (MoveAssignable) 的要求,但不满足可复制构造 (CopyConstructible) 或可复制赋值 (CopyAssignable) 的要求。
总结起来就是:=或者reset都会转移unique_ptr的控制权,并调用析构函数。
我们注意到此处有一个make_unique的非成员函数。
一般来说,我们创建一个unique_ptr有两种方法
1 auto autoMars = std::make_unique<Mars>();//第一种 2 autoMars->prin(); 3 Mars *mars = new Mars;//第二种 4 std::unique_ptr<Mars> pMars(mars);
为什么呢?
使用unique_ptr
并不能绝对地保证异常安全。看一个例子
func(unique_ptr<T>{ new T }, func_throw_exception());
在c++标准中,并没有规定参数运行调用的顺序,所以可能会出现以下调用顺序。
- new T
-
func_throw_exception
-
unique_ptr<T>
这样就导致,new出来的东西可能在抛异常之后无法回收!
func(make_unique<T>(), func_throw_exception()); //改成这样就可以避免上述问题。
参考文档如下,感谢!
官方文档:https://zh.cppreference.com/w/cpp/memory/unique_ptr
主要思路:http://senlinzhan.github.io/2015/04/20/%E8%B0%88%E8%B0%88C-%E7%9A%84%E6%99%BA%E8%83%BD%E6%8C%87%E9%92%88/
demo思路:http://www.cnblogs.com/TenosDoIt/p/3456704.html