深入 C++ 的 unique_ptr

避免错误的使用自定义unique_ptr deleter带来不必要的开销 无意间看到 FOCUS:现代 C++:一文读懂智能指针​zhuanlan.zhihu.com https://zhuanlan.zhihu.com/p/150555165 昂,一个unique_ptr要用40字节???第一反应是作者是不是笔误多打了个0?然而细看一下不对啊,这里应该是用64位测的,一个raw pointer是8字节,那应该不是笔误,再认真细看一下就明白了。 还是从头梳理一下吧,首先要知道unique_ptr和shared_ptr的自定义deleter方式并不一样,unique_p 阅读详情

深入 C++ 的 unique_ptr

从异常安全说起

  使用 raw pointer 管理动态内存时,经常会遇到这样的问题:

  • 忘记delete内存,造成内存泄露。
  • 出现异常时,不会执行delete,造成内存泄露。

  下面的代码解释了,当一个操作发生异常时,会导致delete不会被执行:

1
2
3
4
5
6
7
8
9
void func()
{
auto ptr = new Widget;
// 执行一个会抛出异常的操作
func_throw_exception();
delete ptr;
}

  在 C++98 中我们需要用一种笨拙的方式,写出异常安全的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void func()
{
auto ptr = new Widget;
try {
func_throw_exception();
}
catch(...) {
delete ptr;
throw;
}
delete ptr;
}

  使用智能指针能轻易写出异常安全的代码,因为当对象退出作用域时,智能指针将自动调用对象的析构函数,避免内存泄露:

1
2
3
4
5
6
void func()
{
std::unique_ptr<Widget> ptr{ new Widget };
func_throw_exception();
}

unique_ptr 的原理

  让我们了解一下unique_ptr的实现细节:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
namespace std {
template <typename T, typename D = default_delete<T>>
class unique_ptr
{
public:
explicit unique_ptr(pointer p) noexcept;
~unique_ptr() noexcept;
T& operator*() const;
T* operator->() const noexcept;
unique_ptr(const unique_ptr &) = delete;
unique_ptr& operator=(const unique_ptr &) = delete;
unique_ptr(unique_ptr &&) noexcept;
unique_ptr& operator=(unique_ptr &&) noexcept;
// ...
private:
pointer __ptr;
};
}

  从上面的代码中,我们可以了解到:

  • unique_ptr内部存储一个 raw pointer,当unique_ptr析构时,它的析构函数将会负责析构它持有的对象。
  • unique_ptr提供了operator*()和operator->()成员函数,像 raw pointer 一样,我们可以使用*解引用unique_ptr,使用->来访问unique_ptr所持有对象的成员。
  • unique_ptr并不提供 copy 操作,这是为了防止多个unique_ptr指向同一对象。
  • 但unique_ptr提供了 move 操作,因此我们可以用std::move()来转移unique_ptr。

  很显然,缺省情况下,unique_ptr会使用delete析构对象,不过我们可以使用自定义的 deleter。

1
2
3
4
5
6
7
struct Widget{ };
// ...
auto deleter = []( Widget *p ) {
cout << "delete Widget!" << endl;
delete p;
};
unique_ptr<Widget, decltype(deleter)> ptr{ new Widget, deleter };

  当然,我们可以使用 C++11 的 alias template 特性,这样就可以避免指定 deleter 的类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
struct Widget{ };
template <typename T>
using uniquePtr = unique_ptr<T, void(*)(T*)>;
void func()
{
uniquePtr<Widget> ptr( new Widget,
[]( Widget *p ) {
cout << "delete Widget!" << endl;
delete p;
});
}

  unique_ptr为数组提供了模板偏特化,因此unique_ptr也可以指向数组:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
namespace std {
template <typename T, typename D>
class unique_ptr<T[], D>
{
public:
// ...
T& operator[]( size_t i ) const;
};
template <typename T>
class default_delete<T[]>
{
public:
// ...
void operator()( T *p ) const; // call delete[] p
};
}

  当unique_ptr指向数组时,可以使用[]来访问数组元素。default_delete也为数组提供模板偏特化,因此当unique_ptr被销毁时,会调用delete []释放数组内存。

1
2
3
unique_ptr<string[]> ptr{ new string[100] };
ptr[0] = "hello";
ptr[1] = "world";

一些陷阱

  unique_ptr是用来独占地持有对象的,所以通过同一原生指针来初始化多个unique_ptr,下面是一种错误的使用方式:

1
2
3
4
struct Widget{ };
Widget *ptr = new Widget;
unique_ptr<Widget> p1{ ptr };
unique_ptr<Widget> p2{ ptr }; // ERROR: multiple ownership

  当p1和p2各自被销毁的时候,它们指向的Widget将被delete两次。

再谈异常安全

  C++14 提供了std::make_unique<T>()函数用来直接创建unique_ptr,但 C++11 并没有提供,不过其实现并不复杂:

1
2
3
4
5
6
template <typename T, typename... Ts>
std::unique_ptr<T> make_unique( Ts&&... params ) {
return std::unique_ptr<T>( new T( std::forward<Ts>(params)... ) );
}
// ...
auto ptr = make_unique<std::string>("senlin");

  思考一下使用make_unique的好处?


  使用unique_ptr并不能绝对地保证异常安全,你可能很惊讶于这个结论。让我们看看一个例子:

1
func(unique_ptr<T>{ new T }, func_throw_exception());

  C++ 标准并没有规定编译器对函数参数的求值次序,所以有可能出现这样的次序:

  • 调用new T分配动态内存。
  • 调用func_throw_exception()函数。
  • 调用unique_ptr的构造函数。

  调用func_throw_exception()函数会抛出异常,所以无法构造unique_ptr,导致new T所分配的内存不能回收,造成了内存泄露。解决这个问题,需要使用make_unique函数:

1
func(make_unique<T>(), func_throw_exception());

  这种情况下,成功解决了内存泄露的问题。


  make_unique在初始化对象的时候使用的()而不是{},所以下面的代码显然是初始化10个元素:

1
2
3
auto up = make_unique<vector<int>>( 10, 100 );
cout << "size: " << up->size() << endl;
// size: 10

  但是如果使用std::initializer_list来初始化对象时,要怎样做呢?嗯嗯,看看下面的代码:

1
2
3
4
auto initList = { 1, 2, 3, 4, 5 };
auto up = make_unique<vector<int>>( initList );
cout << "size: " << up->size() << endl;
// size: 5
实战c++中的智能指针unique_ptr系列-- unique_ptr的get_deleter方法(自定义删除器) unique_ptr的成员函数在上一篇博客中几乎全部涵盖,其实还有一个很有踢掉,即std::unique_ptr::get_deleter字面已经很明显了,就获得deleter: Returns the stored deleterThe stored deleter is a callable object. A functional call to this object with a sin 阅读详情

相关推荐

c++: c++ unique_ptr使用

unique_ptr使用场景1、为动态申请的资源提供异常安全保证我们先来看看下面这一段代码:void Func() { int *p = new int(5); // ...(可能会抛出异常) delete p; }这是我们传统的写法:当我们动态申请内存后,有可能我们接下来的代码由于抛出异常或者提前退出(if语句)而没有执行delete操作。解决的方法是使用unique...

DinnerHowe的博客 4863

C++智能指针unique_ptr 详解

一、智能指针 C++智能指针是包含重载运算符的类,其行为像常规指针,但智能指针能够及时、妥善地销毁动态分配的数据,并实现了明确的对象生命周期,因此更有价值。 二、unique_ptr 简介 unique_ptr 是从 C++ 11 开始,定义在 <memory> 中的智能指针(smart pointer)。它持有对对象的独有权,即两个 unique_ptr 不能指向一个对象,不能进行复制操作只能进行移动操作。 unique_ptr 之所以叫这个名字,是因为它智能指向一个对象,即当它指向其

sinat_31608641的博客 9585

C++ unique_ptr与shared_ptr析构的一点区别

struct Base { Base() { std::cout << "Base::构造" << std::endl; } ~Base() { //非virtual std::cout << "Base::~析构" << std::endl; } virtual void ex...

LU_ZHAO的博客 1513

智能指针的deleter机制

智能指针的deleter机制是指,当智能指针的引用计数降为0时,智能指针会自动调用一个指定的析构函数(deleter)来释放所管理的内存。这个析构函数通常是一个函数对象,可以是一个函数指针、一个lambda表达式或者一个重载了函数调用运算符的类对象。智能指针的deleter机制可以确保在任何情况下都能正确地释放内存,包括在异常情况下和多线程环境下。

sinat_31608641的博客 1008

C++:智能指针(1)——auto_ptr, unique_ptr的区别

正在上传…重新上传取消 auto_ptr, unique_ptr 首先看一段代码 #include <iostream> #include <type_traits> #include <vector> #include <memory> #include <exception> using namespace std; int...

weixin_41442027的博客 3102

【C++】std::unique_ptr

`std::unique_ptr`是C++中管理动态内存的首选智能指针,它提供了独占式拥有和自动释放资源的能力,能够有效地避免内存泄漏和资源浪费。通过深入理解`std::unique_ptr`的基本概念、内部原理、应用场景和使用技巧,并结合实际的案例分析,可以更好地掌握和应用这一强大的工具,提高程序的健壮性和性能。

Hi, Boy 1371

C++的智能指针auto_ptr、unique_ptr源码解析

C++的智能指针auto_ptr、unqiue_ptr源码解析1、前言2、源码准备3、源码解析3.1、auto_ptr解析3.2、unqiue_ptr解3.3、unqiue_ptr的一个偏特化版本4、智能指针相关内容的总结5、总结 1、前言 本文仅对C++智能指针auto_ptr、unqiue_ptr源码进行解析,需要读者有一定的C++基础并且对智能指针有所了解,本文并不对智能指针的使用方法、使用场景、效率等方面进行阐述分析,这些知识需自行查阅相关书籍去了解。 建议大家先看一下这篇文章《C++11的智能指

游戏行业资深搬砖人员 3426

C++(11):通过unique_ptr的deleter管理资源

unique_ptr可以用来管理在堆上分配的指针,智能指针唯一的拥有着指针,并在离开作用域时释放堆空间上分配的内存资源: 但资源并不是只有内存一种,有的时候可能会希望其他资源也能拥有这样的管理方式。unique_ptr可以通过deleter来定制化的完成对资源的释放。...

风静如云的博客 1350

C++ scoped_ptr 和 unique_ptr

/ 文件指针的自定义删除器// 文件会自动关闭return 0;scoped_ptr:简单的独占所有权,适用于不需要移动语义的简单场景unique_ptr:功能丰富的独占所有权指针,是现代 C++ 的首选推荐使用unique_ptr它是 C++ 标准的一部分支持移动语义,更灵活有更好的容器兼容性支持自定义删除器和数组在现代 C++ 开发中,应该优先使用unique_ptr来管理独占所有权的资源,避免使用原始指针和scoped_ptr。设计原则默认使用。

FantasticOrange的博客 1555

C++ unique_ptr实践代码详解

unique_ptr是C++11标准中引入的一种智能指针,用于自动管理单个对象的生命周期。它确保在其析构时自动释放所拥有的对象。这是通过在unique_ptr对象销毁时,调用内置的delete运算符或者用户提供的自定义删除器来完成的。unique_ptr的特点如下:唯一所有权:一个unique_ptr对象在同一时间只能指向一个对象,从而确保资源的唯一所有权。转移语义unique_ptr对象不能拷贝,只能移动。这意味着所有权可以在unique_ptr。

weixin_42590539的博客 1170

ANSYS Fluent 2023R2实战:用欧拉多相流模型搞定流化床模拟(附详细参数避坑)

本文详细解析了ANSYS Fluent 2023R2中欧拉多相流模型在流化床模拟中的应用,包括模型选择、材料属性设置、相间作用力配置及初始化技巧。特别针对高颗粒浓度工况提供参数优化方案,帮助工程师提升模拟精度与效率,适用于化工、能源等领域的流化床反应器设计。

weixin_30938149的博客 269

【C++11】 智能指针 std::unique_ptr 详解

参考: 1. std::unique_ptr 是 C++11 起引入的智能指针。为什么必须要在 C++11 起才有该特性,主要还是 C++11 增加了move语义,否则无法对对象的所有权进行传递。 1. unique_ptr 介绍: unique_ptr 不共享它的指针。它无法复制到其他 unique_ptr,无法通过值传递到函数,也无法用于需要副本的任何标准模板库 (STL) 算法。只能移动unique_ptr。这意味着,内存资源所有权将转移到另一 unique_ptr,并且原始 unique_pt.

lemonxiaoxiao的博客 11万+

Pcileech(DMA)开源项目简述

希望大DMA家能正确认识FPGA,正确使用DMA技术,对于市场上各类伪装成花里胡哨设备的FPGA板卡它的本质是不会变的,不要上当受骗。

2301_79773847的博客 5964

C++11 unique_ptr用法

unique_ptr不共享它的指针。它无法复制到其他unique_ptr,无法通过值传递到函数,也无法用于需要副本的任何标准模板库 (STL) 算法。只能移动unique_ptr。这意味着,内存资源所有权将转移到另一unique_ptr,并且原始unique_ptr不再拥有此资源。我们建议你将对象限制为由一个所有者所有,因为多个所有权会使程序逻辑变得复杂。因此,当需要智能指针用于纯 C++ 对象时,可使用unique_ptr,而当构造unique_ptr时,可使用make_uniqueHe...

jusu10的博客 2402

DC综合中set_dft_signal的实战配置与优化策略

本文深入解析了DC综合中set_dft_signal命令的实战配置与优化策略。文章从命令的核心作用出发,详细拆解了-view、-type、-usage等关键参数,并通过扫描使能与时钟门控的实战案例,展示了如何正确配置以实现测试模式下的功耗优化。同时,文章总结了高级优化策略、与低功耗流程的协同方法以及常见错误排查清单,旨在帮助数字芯片设计工程师构建高可测性、低功耗的稳健DFT基础。

weixin_28347369的博客 403

影刀RPA验证码识别避坑指南:官方指令、Python ddddocr与第三方图鉴怎么选?

本文深度对比了影刀RPA验证码识别的三种方案:官方AI指令、Python ddddocr开源库和第三方图鉴服务。从识别率、成本、维护性等维度分析各方案优劣,提供实战选型建议和优化技巧,帮助技术决策者在自动化流程中高效解决验证码识别难题。

weixin_30790841的博客 471

c++11 unique_ptr 与 make_unique源码剖析

写在最前。。。 0. 前言 所谓智能指针,可以从字面上理解为“智能”的指针。具体来讲,智能指针和普通指针的用法是相似的,不同之处在于,智能指针可以在适当时机自动释放分配的内存。也就是说,使用智能指针可以很好地避免“忘记释放内存而导致内存泄漏”问题出现。由此可见,C++ 也逐渐开始支持垃圾回收机制了,尽管目前支持程度还有限。 c++11 中发布了shared_ptr、unique_ptr、weak_ptr 用以资源的管理,都是定义在memory 这个头文件中。 std::shared_pt..

私房菜 9038

FOC无刷电机磁编码器机械角度与电角度自动对齐校准及电机极对数自动获取的方法

本文提出磁编码器机械角度与电角度自动对齐校准方法及电机极对数自动获取方案。通过通直流电流使转子定向,读取机械角度并计算电角度偏移量,实现精确对齐;同时利用低速旋转时检测反电动势过零点次数,结合机械角度变化量自动计算极对数。核心算法包括转子定向、偏移量计算、极对数推导等步骤,并提供了基于STM32的C语言实现代码。该方法适用于工业伺服、机器人等高精度控制场景,需注意负载安全、参数调整和误差处理。两种自动化流程可有效解决电机安装调试中的角度对齐和参数识别问题。

qq_29653575的博客 2489

C++11-unique_ptr详解

在《拥抱智能指针,告别内存泄露》中说到了内存泄漏问题,也提到了C++中的智能指针基本原理,今天就来说说类模板unique_ptr。 在此之前,先回答读者的一个提问:C语言中该怎么办?有几点建议: 编写时尽量遵循函数内申请,函数内释放的原则 注意成对编写malloc和free 使用静态扫描工具,如《pclint检查》 使用内存检测工具,如valgrind unique_ptr 一个unique_ptr独享它指向的对象。也就是说,同时只有一个unique_ptr指向同一个对象,当这个unique_ptr被销

ShinDebonair 4261

使用Qt编译Qt WebEngine

这就是使用Qt编译Qt WebEngine模块的基本步骤。通过按照上述步骤,您应该能够成功编译和使用Qt WebEngine来嵌入Web内容到您的Qt应用程序中。Qt WebEngine是Qt框架的一个模块,它提供了一个现代的Web浏览器引擎,可以在Qt应用程序中嵌入Web内容。首先,需要获取Qt的源代码。如果尚未安装,可以从Qt官方网站下载并安装Qt。完成Qt的安装后,您可以构建并运行Qt WebEngine示例来验证编译是否成功。这将把编译好的Qt库文件和头文件安装到之前指定的安装目录中。

DevForge的博客 3017

句向量(句嵌入)模型sent2vec的训练及应用

本文讨论NLP中的句向量模型(sent2vec),也就是将一个完整的句子映射成一个实数向量的技术。这方面已经发表的成果也是比较多的,本文中所涉及的技术主要源自NAACL 2018的一篇论文,其中提出的sent2vec模型可以理解为词嵌入技术中经典的CBOW方法的扩展,该所谓的扩展中一个重要改进就是引入了n-gram

白马负金羁 1万+

C++智能指针 shared_ptr 和 unique_ptr

传统C/C++编程中,使用new或者malloc动态申请内存后,必须手动调用delete或者free去释放,否则就会造成内存泄漏。在C++ 11语法中,提供了智能指针来管理内存,开发者不必再关心内存的释放问题,智能指针可以自动去释放管理的内存空间。

new9232的博客 1459

Experion PKS系列开发:I_O模块_ExperionPKS与第三方I-O模块的集成

通过上述步骤,可以成功将第三方I/O模块集成到Honeywell Experion PKS系统中,实现对现场设备的监视和控制。集成过程中需要注意选择合适的第三方模块,配置正确的通信参数,编写正确的控制逻辑,并进行充分的测试,以确保系统的稳定性和可靠性。不同的通信协议(如Modbus、Profibus、Ethernet/IP、CANopen、OPC UA)有其独特的配置和编程方法,但总体流程相似。在实际应用中,根据项目需求选择合适的协议和模块,可以有效提高系统的灵活性和适应性。

zhubeibei168的博客 1103

C++中的shared_ptr和unique_ptr

默认使用unique_ptr适用于大多数单一所有权场景性能最优,语义最清晰需要共享时使用shared_ptr配合weak_ptr避免循环引用用于缓存、观察者等共享场景避免裸new/delete始终使用智能指针管理动态资源优先使用提供异常安全保证更高效的内存布局(特别是接口设计明确所有权函数参数和返回值清晰表达所有权转移意图通过合理选择智能指针类型,可以显著提高 C++ 代码的安全性、可读性和可维护性,同时减少内存管理相关的错误。

gdr12的专栏 1265

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

C++智能指针unique_ptr与shared_ptr

文章目录1.unique_ptr特点2.unique_ptr例子3.unique_ptr总结4.shared_ptr特点5.shared_ptr例子6.shared_ptr中的自定义删除器 Deleter7.shared_ptr 相对于普通指针的优缺点 1.unique_ptr特点 unique_ptr 是 C++ 11 提供的用于防止内存泄漏的智能指针中的一种实现,独享被管理对象指针所有权的智能指针。 unique_ptr对象包装一个原始指针,并负责其生命周期。当该对象被销毁时,会在其析构函数中删除关联

喜欢打篮球的普通人 7014

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

unique_ptr是什么?如果在C++中自己实现unique_ptr,应当如何实现?

是 C++11 引入的一种智能指针。它拥有对其所指向对象的独占所有权唯一所有权:在任何时刻,只有一个unique_ptr实例可以拥有一个给定的对象。自动销毁:当unique_ptr被销毁(例如离开作用域)时,它所拥有的对象会自动被删除,其内存会被释放。移动语义:虽然unique_ptr不能被复制,但所有权可以通过移动语义(Move Semantics)安全地转移给另一个unique_ptr。它的主要目的是替代new和delete,管理对象的生命周期,从而有效防止内存泄漏,并明确表达代码的所有权语义。

weixin_51775138的博客 1102

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

上一篇: redis中服务器流程分析
下一篇: c++ 智能指针用法详解
TuxedoLinux
博客等级 码龄9年 268粉丝 34原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值