智能指针 unique_ptr 详解
一、智能指针
1.什么是智能指针
简单地说,C++智能指针是包含重载运算符的类,其行为像常规指针,但智能指针能够及时、妥善地销毁动态分配的数据,并实现了明确的对象生命周期,因此更有价值。
2.常规指针存在的问题
C++在内存分配、释放和管理方面向程序员提供了全面的灵活性。但是这种灵活性是把双刃剑,一方面它使C++成为一种功能强大的语言,另一方面它让程序员能够制造与内存相关的问题,比如内存泄漏(用完未释放,遗漏掉了)。
例如在堆声明和分配的内存,析构方法是否会自动销毁对象,又或是方法结束后需要一个个释放,方法存在很多返回的地方,每个返回语句都要执行很多相关释放操作,十分繁琐,用智能指针就能实现其自动释放。
3.智能指针有何帮助
鉴于使用常规指针存在的问题,当C++程序猿需要管理堆中的数据时,可使用智能指针的方式分配和管理内存。
4.智能指针
智能指针类重载了解除引用运算符(*)和成员选择运算符(->)。
同时为了能够在堆中管理各种类型,几乎所有的智能指针都是模板类,包含其功能的泛型实现。
二、unique_ptr 简介
1.概念
unique_ptr 是从 C++ 11 开始,定义在 <memory> 中的智能指针(smart pointer)。它持有对对象的独有权,即两个 unique_ptr 不能指向一个对象,不能进行复制操作只能进行移动操作。
unique_ptr 之所以叫这个名字,是因为它只能指向一个对象,即当它指向其他对象时,之前所指向的对象会被摧毁。其次,当 unique_ptr 超出作用域时,指向的对象也会被自动摧毁,帮助程序员实现了自动释放的功能。
unique_ptr 也可能还未指向对象,这时的状态被称为 empty。
2.简单示例
std::unique_ptr<int>p1(new int(5));
std::unique_ptr<int>p2=p1;// 编译会出错
std::unique_ptr<int>p3=std::move(p1);// 转移所有权, 现在那块内存归p3所有, p1成为无效的针.
p3.reset();//释放内存.
p1.reset();//无效
三、unique_ptr 详解
1.定义
unique_ptr 在 <memory> 中的定义如下:
// non-specialized
template <class T, class D = default_delete<T>> class unique_ptr;
// array specialization
template <class T, class D> class unique_ptr<T[],D>;
其中 T 指其管理的对象类型,D 指该对象销毁时所调用的释放方法,可以使用自定义的删除器,他也有一个默认的实现,即 detele 操作。
2.常用方法介绍
2.1 构造方法 std::unique_ptr::unique_ptr
// unique_ptr constructor example
#include <iostream>
#include <memory>int main () {std::default_delete<int> d;std::unique_ptr<int> u1;std::unique_ptr<int> u2 (nullptr);std::unique_ptr<int> u3 (new int);std::unique_ptr<int> u4 (new int, d);std::unique_ptr<int> u5 (new int, std::default_delete<int>());std::unique_ptr<int> u6 (std::move(u5));std::unique_ptr<int> u7 (std::move(u6));std::unique_ptr<int> u8 (std::auto_ptr<int>(new int));std::cout << "u1: " << (u1?"not null":"null") << '\n';std::cout << "u2: " << (u2?"not null":"null") << '\n';std::cout << "u3: " << (u3?"not null":"null") << '\n';std::cout << "u4: " << (u4?"not null":"null") << '\n';std::cout << "u5: " << (u5?"not null":"null") << '\n';std::cout << "u6: " << (u6?"not null":"null") << '\n';std::cout << "u7: " << (u7?"not null":"null") << '\n';std::cout << "u8: " << (u8?"not null":"null") << '\n';return 0;
}
执行结果为:
u1: null
u2: null
u3: not null
u4: not null
u5: null
u6: null
u7: not null
u8: not null
2.2 析构方法 std::unique_ptr::~unique_ptr
// unique_ptr destructor example
#include <iostream>
#include <memory>int main () {// user-defined deleterauto deleter = [](int*p){delete p;std::cout << "[deleter called]\n";};std::unique_ptr<int,decltype(deleter)> foo (new int,deleter);std::cout << "foo " << (foo?"is not":"is") << " empty\n";return 0; // [deleter called]
}
执行结果为:
foo is not empty
[deleter called]
2.3 释放方法 std::unique_ptr::release
注意!注意!注意!这里的释放并不会销毁其指向的对象,而且将其指向的对象释放出去。
// unique_ptr::release example
#include <iostream>
#include <memory>int main () {std::unique_ptr<int> auto_pointer (new int);int * manual_pointer;*auto_pointer=10;manual_pointer = auto_pointer.release();// (auto_pointer is now empty)std::cout << "manual_pointer points to " << *manual_pointer << '\n';delete manual_pointer;return 0;
}
执行结果为:
manual_pointer points to 10
2.4 重置方法 std::unique_ptr::reset
// unique_ptr::reset example
#include <iostream>
#include <memory>int main () {std::unique_ptr<int> up; // emptyup.reset (new int); // takes ownership of pointer*up=5;std::cout << *up << '\n';up.reset (new int); // deletes managed object, acquires new pointer*up=10;std::cout << *up << '\n';up.reset(); // deletes managed objectreturn 0;
}
执行结果为:
5
10
2.5 交换方法 std::unique_ptr::swap
// unique_ptr::swap example
#include <iostream>
#include <memory>int main () {std::unique_ptr<int> foo (new int(10));std::unique_ptr<int> bar (new int(20));foo.swap(bar);std::cout << "foo: " << *foo << '\n';std::cout << "bar: " << *bar << '\n';return 0;
}
执行结果为:
foo: 20
bar: 10
四、自定义删除器详解
1.为什么要使用自定义的删除器
当你的对象不能仅仅只是依靠 delete 删除时,那么你就需要依靠自定义的删除器了。例如对象中还有其它对象的数组等。
2.怎么写
主要就是自己编写一个删除器,指定输入的参数,然后实现相应的释放操作,并将这个删除器传入 unique_ptr 中。
3.实例分析
3.1 开发中经常会使用到图片,假设有这么一个图片的结构体定义如下
/// 图像格式定义
typedef struct cv_image_t {unsigned char *data; ///< 图像数据指针cv_pixel_format pixel_format; ///< 像素格式int width; ///< 宽度(以像素为单位)int height; ///< 高度(以像素为单位)int stride; ///< 跨度, 即每行所占的字节数
} cv_image_t;
3.2 再写一个图片的释放方法
void cv_image_release(cv_image_t* image) {if(!image) {return;}delete[] image->data;delete image;return;
}
3.3 然后我们在代码中就可以使用一个如下的智能指针来智能的控制图片的释放操作了
cv_image_t image_input = { (unsigned char*) image,pixel_format,image_width,image_height,image_stride
};
std::unique_ptr<cv_image_t, decltype(cv_image_release)*> image_guard (image_input , cv_image_release);
3.4 优化写法
应用中很多地方都要使用图片,然后都需要这样一个图片的智能指针,不过每次都写这么一长串很麻烦,而且定义也都是一样的,那么我们就可以简单的封装一下,比如可以定义一个 cv_image_ptr 专门,如下:
struct cv_image_destructor{void operator()(cv_image_t* img){cv_image_release(img);}
};typedef std::unique_ptr<cv_image_t, cv_image_destructor> cv_image_ptr;
这样我们再在代码中使用的时候就方便很多了,例如
cv_image_ptr image_guard;
image_guard.reset(image_input);
而且代码看上去也整洁了很多。
关于 unique_ptr 更官方和详细的说明,可以参考:unique_ptr - C++ Reference
智能指针 unique_ptr 详解相关推荐
- C++ 智能指针 unique_ptr 详解与示例
unique_ptr 是 C++ 11 提供的用于防止内存泄漏的智能指针中的一种实现,独享被管理对象指针所有权的智能指针.unique_ptr对象包装一个原始指针,并负责其生命周期.当该对象被销毁时, ...
- c++智能指针用法详解
随笔 - 209 文章 - 2 评论 - 174 c++ 智能指针用法详解 本文介绍c++里面的四个智能指针: auto_ptr, shared_ptr, weak_ptr, unique_p ...
- c++ 智能指针_详解 C++ 11 中的智能指针
C/C++ 语言最为人所诟病的特性之一就是存在内存泄露问题,因此后来的大多数语言都提供了内置内存分配与释放功能,有的甚至干脆对语言的使用者屏蔽了内存指针这一概念.这里不置贬褒,手动分配内存与手动释放内 ...
- c++ 智能指针用法详解
http://www.cnblogs.com/TenosDoIt/p/3456704.html 本文介绍c++里面的四个智能指针: auto_ptr, shared_ptr, weak_ptr, un ...
- share_ptr智能指针使用详解
share_ptr 智能指针,也被称为共享指针,用于管理可以由多个智能指针共同拥有的动态分配对象.特别是,类型 shared_ptr<T> 用于管理 T 类型对象的所有权. 类构造函数 s ...
- 【C++】智能指针用法详解(非常实用)
一.指针与智能指针的区别 1.指针 C 语言规定所有变量在使用前必须先定义,指定其类型,并按此分配内存单元.指针变量不同于整型变量和其他类型的变量,它是专门用来存放地址的,所以必须将它定义为" ...
- C++智能指针unique_ptr与shared_ptr
文章目录 1.unique_ptr特点 2.unique_ptr例子 3.unique_ptr总结 4.shared_ptr特点 5.shared_ptr例子 6.shared_ptr中的自定义删除器 ...
- C++11中的智能指针unique_ptr、shared_ptr和weak_ptr详解
目录 1.引言 2.什么是智能指针? 3.在Visual Studio中查看智能指针的源码实现 4.独占式指针unique_ptr 4.1.查看unique_ptr的源码实现片段 4.2.为什么uni ...
- 如何使用指向类的成员函数的指针(详解!)
原文:如何使用指向类的成员函数的指针(详解!) 另外一篇英文参考:Member Function Pointers and the Fastest Possible C++ Delegates 我们首 ...
最新文章
- 清华北大,已经没人本科就找工作了
- Okhttp3中设置超时的方法
- C#.NET Thread多线程并发编程学习与常见面试题解析-1、Thread使用与控制基础
- PBR:双向反射分布函数(BRDF)介绍与Cook-Torrance模型的实现
- 【2019.09.07】2019徐州网络赛
- WannaCry只是个开始?信息时代你急需的安全书单
- mysql获取某个表的所有字段名
- OpenCV-图像处理(32、点多边形测试)
- Unti12. linux中的软件的管理
- h30-t10 android phone,荣耀3C移动2G版(H30-T10)官方完整版ROM全合集!!!
- 【LeetCode LCP 3】机器人大冒险
- dnf红眼补丁在哪下载_dnf红眼技能变红补丁
- 网络协议 18 - CDN:家门口的小卖铺 1
- 来了超火爆的Java游戏羊了个羊_java开发游戏项目
- 从零开始搭建公司后台技术栈
- 创建表空间(Oracle)
- umijs介绍及基本用法、配置式路由、约定式路由、路由传参等
- Ruby way Rails way Milky way
- 人工智能合一算法java语言实现_人工智能合一算法UNify.doc
- 开关电源(DC-DC)与LDO电源的区别---纹波