网站首页 > 文章精选 正文
0.简介
unique_ptr是C++11引入的一种独占所有权的智能指针,其提供了自动管理内存的能力,同时保持有和裸指针相近的性能开销。本文将原理,源码和使用来进行介绍。
1.背景介绍(从问题来看其必要性)
在开发C++代码过程中,通过手动管理内存,常常存在以下问题:
1)内存泄漏(忘记delete)和悬垂指针(被提前delete):这也是所有智能指针要解决的核心问题。
2)所有权不明确:谁负责释放的问题,这个不同的智能指针有着自己的计算方式,shared_ptr通过引用计数,在哪引用计数减为0就在哪释放;而unique_ptr通过独占所有权,谁最后占用谁出作用域释放。
2.原理
unique_ptr的设计其实比较简单,像模板等在shared_ptr文章中有相应介绍,不再赘述,只看其核心的设计思想。
1)独占所有权:同一时间只能有一个unique_ptr指向某个对象,其被销毁时,其管理的对象也一并销毁。
2)转移而不拷贝:所有权通过移动语义转移,不能通过拷贝赋值。
3)轻量级设计:操作接近原始指针。
4)可定制删除器:和shared_ptr一样,unique_ptr也可以定制删除器。
3.源码解读
源码解读部分我们还是先看其成员变量,其成员变量就只有一个,也就是__uniq_ptr_impl,其内部成员如下,通过一个tuple来存储原始指针和自定义删除器:
tuple<pointer, _Dp> _M_t;
看完成员变量后,我们来看其成员函数定义,首先看如何实现不允许拷贝,只允许移动,其通过delete拷贝构造函数来实现。
// Disable copy from lvalue.
unique_ptr(const unique_ptr&) = delete;
unique_ptr& operator=(const unique_ptr&) = delete;
接下来来看一下make_unique的实现,其通过完美转发将参数转给new运算符,构造出原始指针,然后传给构造函数就可以。
/// std::make_unique for single objects
template<typename _Tp, typename... _Args>
inline typename _MakeUniq<_Tp>::__single_object
make_unique(_Args&&... __args)
{ return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
/// std::make_unique for arrays of unknown bound
template<typename _Tp>
inline typename _MakeUniq<_Tp>::__array
make_unique(size_t __num)
{ return unique_ptr<_Tp>(new remove_extent_t<_Tp>[__num]()); }
/// Disable std::make_unique for arrays of known bound
template<typename _Tp, typename... _Args>
inline typename _MakeUniq<_Tp>::__invalid_type
make_unique(_Args&&...) = delete;
再来看一下析构,其根据设置的释放器来进行释放:
/// Destructor, invokes the deleter if the stored pointer is not null.
~unique_ptr() noexcept
{
static_assert(__is_invocable<deleter_type&, pointer>::value,
"unique_ptr's deleter must be invocable with a pointer");
auto& __ptr = _M_t._M_ptr();
if (__ptr != nullptr)
get_deleter()(std::move(__ptr));
__ptr = pointer();
}
4.使用方式
其基本使用方式可以参考如下:
#include <iostream>
#include <memory>
class MyClass {
public:
MyClass() { std::cout << "MyClass created" << std::endl; }
~MyClass() { std::cout << "MyClass destroyed" << std::endl; }
void doSomething() { std::cout << "Doing something..." << std::endl; }
};
int main() {
// 创建方式一:使用make_unique(C++14及以后)
auto ptr1 = std::make_unique<MyClass>();
ptr1->doSomething();
// 创建方式二:使用构造函数(C++11)
std::unique_ptr<MyClass> ptr2(new MyClass());
// 错误:不能拷贝unique_ptr
// std::unique_ptr<MyClass> ptr3 = ptr1; // 编译错误
// 正确:可以移动unique_ptr
std::unique_ptr<MyClass> ptr3 = std::move(ptr1);
if (ptr1 == nullptr) {
std::cout << "ptr1 is now null" << std::endl;
}
// 通过reset()释放所有权
ptr2.reset(); // 显式释放资源
// 通过release()转移所有权
MyClass* rawPtr = ptr3.release(); // ptr3变为空
delete rawPtr; // 需要手动释放
return 0;
}
- 上一篇: Qt 智能指针学习
- 下一篇: C++11新特性总结 (二)
猜你喜欢
- 2025-08-02 C++开发者都应该使用的十个C++11特性(上)
- 2025-08-02 如何实现自己的C++ unique_ptr?
- 2025-08-02 刚学会C++的小白用这个开源框架,做个 RPC 服务要多久?
- 2025-08-02 C++11+ 泛型编程(模板)
- 2025-08-02 abelkhan中的rpc框架
- 2025-08-02 C++设计模式:用代码演绎武侠世界的绝世神功
- 2025-08-02 视频分析与对象跟踪-扩展模块的单目标和多目标跟踪
- 2025-08-02 ROS2开发实践:ROS核心(节点、话题、服务、DDS通信协议等)
- 2025-08-02 C++语言程序员编程必收藏的20个经典实战案例(附完整源码)
- 2025-08-02 C# 控制电脑睡眠,休眠,关机以及唤醒
- 最近发表
- 标签列表
-
- newcoder (56)
- 字符串的长度是指 (45)
- drawcontours()参数说明 (60)
- unsignedshortint (59)
- postman并发请求 (47)
- python列表删除 (50)
- 左程云什么水平 (56)
- 编程题 (64)
- postgresql默认端口 (66)
- 数据库的概念模型独立于 (48)
- 产生系统死锁的原因可能是由于 (51)
- 数据库中只存放视图的 (62)
- 在vi中退出不保存的命令是 (53)
- 哪个命令可以将普通用户转换成超级用户 (49)
- noscript标签的作用 (48)
- 联合利华网申 (49)
- swagger和postman (46)
- 结构化程序设计主要强调 (53)
- 172.1 (57)
- apipostwebsocket (47)
- 唯品会后台 (61)
- 简历助手 (56)
- offshow (61)
- mysql数据库面试题 (57)
- fmt.println (52)