当前位置: 代码迷 >> 综合 >> C++11智能指针-unique_ptr
  详细解决方案

C++11智能指针-unique_ptr

热度:79   发布时间:2024-03-06 19:29:46.0

 前面介绍了C++98 的智能指针auto_ptr,现在来介绍一下它的替代品【unique_ptr】

看完,我也是醉了。好吧 我们继续

 auto_ptr是用于C++11之前的智能指针。由于 auto_ptr 基于排他所有权模式:两个指针不能指向同一个资源,复制或赋值都会改变资源的所有权。auto_ptr 主要有三大问题:

  • 复制和赋值会改变资源的所有权,不符合人的直觉。
  • 在 STL 容器中使用auto_ptr存在重大风险,因为容器内的元素必需支持可复制(copy constructable)和可赋值(assignable)。
  • 不支持对象数组的操作

先来看看auto_ptr的风险

#include <iostream>
#include <memory>
#include <vector>
#include <Windows.h>
#include <string>
#include <stdio.h>using namespace std;int
main(int argc, const char* argv[])
{auto_ptr<string> str_ptr1(new string("Libero"));auto_ptr<string> str_ptr2(new string("Martin"));// 被C++11 抛弃的主要理由 p1= p2 ,复制或赋值都会改变资源的所有权printf("str_ptr1: %p\n", str_ptr1.get());printf("str_ptr2: %p\n", str_ptr2.get());printf("after str_ptr1 = str_ptr2;\n");str_ptr1 = str_ptr2;printf("str_ptr1: %p\n", str_ptr1.get());printf("str_ptr2: %p\n", str_ptr2.get());//弊端2. 在 STL 容器中使用auto_ptr存在重大风险,//因为容器内的元素必需支持可复制(copy constructable)和可赋值(assignable)。vector<auto_ptr<string>> va_ptr;auto_ptr<string> str_ptr3(new string("I am Libero"));auto_ptr<string> str_ptr4(new string("I am Martin"));va_ptr.push_back(std::move(str_ptr3));va_ptr.push_back(std::move(str_ptr4));for (auto itor = va_ptr.cbegin(); itor != va_ptr.cend(); ++itor) {cout << *(*itor) << endl;}// 风险来了va_ptr[0] = va_ptr[1];cout << "va_ptr[0]: " << *va_ptr[0] << endl;cout << "va_ptr[1]: " << *va_ptr[1] << endl;//弊端3. 不支持对象数组的内存管理//auto_ptr<int[]> ai(new int[5]);  //不能这样定义system("pause");return 0;
}

看完了auto_ptr 我们在来看一看 unique_ptr

unique_ptr特性

  1. 基于排他所有权模式:两个指针不能指向同一个资源
  2. 无法进行左值unique_ptr复制构造,也无法进行左值复制赋值操作但允许临时 右值赋值构造和赋值
  3. 保存指向某个对象的指针,当它本身离开作用域时会自动释放它指向的对象。
  4. 在容器中保存指针是安全的
    unique_ptr<string> str_ptr1(new string("Libero"));unique_ptr<string> str_ptr2(new string("Martin"));printf("str_ptr1: %p\n", str_ptr1.get());printf("str_ptr2: %p\n", str_ptr2.get());printf("after str_ptr1 = str_ptr2;\n");str_ptr1 = std::move(str_ptr2);   // 必须要把 左值转成右值【就非常的nice,很细节】printf("str_ptr1: %p\n", str_ptr1.get());printf("str_ptr2: %p\n", str_ptr2.get());unique_ptr<string> str_ptr3(new string("I am Libero"));unique_ptr<string> str_ptr4(std::move(str_ptr3));vector<unique_ptr<string>> vu_ptr;vu_ptr.push_back(std::move(str_ptr3));vu_ptr.push_back(std::move(str_ptr4));for (auto itor = vu_ptr.cbegin(); itor != vu_ptr.cend(); ++itor) {cout << (*itor).get() << endl;}unique_ptr<int[]> ui(new int[5]);  //自动会调用 delete []函数去释放

效果:

思考:为什么说相比于auto_ptr  的 str_ptr1 = str_ptr2, unique_ptr的str_ptr1 = std::move(str_ptr2)更好呢?

诶不都是 把 str_ptr2的 _Myptr置空了嘛,为什么呢后者更好呢 ?

因为后者 std::move 这个操作不仅会提醒 程序员 ,诶这个操作是会把 原来的 str_ptr2的_Myptr弄成无效的哦,后面就不要引用str_ptr2咯!再者 这也符合左值和右值的特点, 如果我们加一个 std::move()就表明 这个是个临时的值 ,后面就不能用它了。在这之前大家要搞清楚什么是 左值 什么是 右值。 左值引用操作的特点,右值引用操作的特点。 

 

 

这些函数如果看不懂unique_ptr源码的可以参考:

构造函数

unique_ptr<T> up ; //空的unique_ptr,可以指向类型为T的对象

unique_ptr<T> up1(new T()) ;//定义unique_ptr,同时指向类型为T的对象

unique_ptr<T[]> up ; //空的unique_ptr,可以指向类型为T[的数组对象

unique_ptr<T[]> up1(new T[]) ;//定义unique_ptr,同时指向类型为T的数组对象

unique_ptr<T,D> up(); //空的unique_ptr,接受一个D类型的删除器d,使用d释放内存

unique_ptr<T,D> up(new T()); //定义unique_ptr,同时指向类型为T的对象,接受一个D   类型的删除器d,使用删除器d来释放内存

 

放弃对象控制权

up.release();    //放弃对象的控制权,返回指针,将up置为空,不会释放内存

重置

up.reset(…) ; //参数可以为 空、内置指针,先将up所指对象释放,然后重置up的值

交换

up.swap(up1);  //将智能指针up 和up1管控的对象进行交换