首页 > 编程语言 >C++: 智能指针的自定义删除器 `Custom Deleter` 有什么用?

C++: 智能指针的自定义删除器 `Custom Deleter` 有什么用?

时间:2023-12-16 13:44:37浏览次数:24  
标签:std 自定义 删除 C++ Custom shared unique ptr

C++11智能指针std::shared_ptrstd::unique_ptr都支持自定义删除器,本文将介绍自定义删除器的使用场景和使用方法。智能指针模板参数的第二个类型是删除器,一般是一个函数指针类型或者是一个函数对象类型。通常情况下,删除器的类型是std::default_delete<T>,它是一个函数对象类型,用于调用delete来释放所管理的对象。

template <typename T, typename Deleter = std::default_delete<T>>
class unique_ptr;
template <typename T, typename Deleter = std::default_delete<T>>
class shared_ptr;

1. 自定义删除器的使用场景

自定义删除器的作用是在智能指针释放所管理的对象时,执行一些特殊的操作,比如:

  • 内存释放时打印一些日志。

  • 管理除内存以外的其它资源,例如文件句柄、数据库连接等。

  • 与自定义分配器(Allocator)配合使用,将资源释放给自定义分配器。

  • 在C++17之前,std::shared_ptr用于管理数组时需要自定义删除器来释放数组内存,因为默认使用delete来释放所管理的对象,而delete不能正确释放分配的数组,需要在自定义删除器delete[]释放数组。

注: C++17 之后,std::shared_ptr可以管理动态分配的数组,因为std::shared_ptr<T[]>默认使用delete[]来释放所管理的对象。

2. 自定义删除器的使用

自定义删除器可以是一个函数,也可以是一个类的对象, 也可以是一个lambda表达式。

如果是一个函数,它的形式如下:

void free_memory(int* p) {
    std::cout << "delete memory" << std::endl;
    delete p;
}

如果是一个类的对象,它的形式如下:

class FreeMemory {
public:
    void operator()(int* p) {
        std::cout << "delete memory" << std::endl;
        delete p;
    }
};

如果是一个lambda表达式,它的形式如下:

auto free_memory_lambda = [](int* p) {
    std::cout << "delete memory" << std::endl;
    delete p;
}

2.1 shared_ptr自定义删除器的使用:

对于shared_ptr, 不管删除器什么类型,是否有状态都不会增加shared_ptr的大小, 均为两个字长。因为删除器是存储在控制块中,而控制块的大小为两个字长。

std::shared_ptr<int> sp1(new int(0), free_memory); // size: 8
std::shared_ptr<int> sp2(new int(0), FreeMemory()); // size: 8
std::shared_ptr<int> sp3(new int(0), free_memory_lambda); // size: 8

2.2 unique_ptr自定义删除器的使用:

  • unique_ptr的删除器类型是一个模板参数,因此需要指定删除器类型。
  • 如果删除器是函数指针类型,std::unique_ptr大小从1个字长增长到2个字长,因为需要存储函数指针。
  • 如果删除器是无状态删除器(stateless function),比如不进行捕获的lambda表达式,std::unique_ptr大小不变,因为无状态删除器不需要存储任何成员变量。
std::unique_ptr<int, FreeMemory> up1(new int(0)); // size: 4
std::unique_ptr<int, void(*)(int*)> up2(new int(0), free_memory);  // size: 8
std::unique_ptr<int, decltype(free_memory)*> up3(new int(0), free_memory); // size: 4

3. 有状态删除器和无状态删除器

什么是有状态删除器?什么是无状态删除器?有状态删除器是指删除器类中包含有成员变量,无状态删除器是指删除器类中不包含有成员变量。

如果std::unique_ptr的函数对象删除器是具有扩展状态的,其大小可能会非常大。如果大得无法接受,可能需要设计一个无状态删除器。

下面是一个有状态删除器的例子:

class DeleteObject {
public:
    DeleteObject(int n) : n_(n) {}
    void operator()(int* p) {
        std::cout << "delete memory " << n_ << std::endl;
        delete p;
    }
private:
    int n_;
};

总结

本文介绍了自定义删除器的使用场景和使用方法,以及有状态删除器和无状态删除器的区别。帮助大家了解自定义删除器的使用方法。

参考

  1. Effective Modern C++, Item 18: Use std::unique_ptr for exclusive-ownership resource management.

你好,我是七昂,计算机科学爱好者,致力于分享C/C++、操作系统、软件架构等计算机基础知识。希望我们能一起探索程序员修炼之道,最终能站得更高,走得更远。如果你有任何问题或者建议,欢迎随时与我交流。如果我的创作内容对您有帮助,请点赞关注。感谢你的阅读。

标签:std,自定义,删除,C++,Custom,shared,unique,ptr
From: https://www.cnblogs.com/qiangz/p/17904766.html

相关文章

  • C++ 高效使用智能指针的8个建议
    C++高效使用智能指针的8个建议前言:智能指针是C++11提供的新特性,它基于RAII实现,可以自动管理内存资源,避免内存泄漏的发生,但是智能指针也并不是万能的,如果不正确使用智能指针,也会导致内存泄漏的发生,因此,我们需要了解如何高效使用智能指针避免一些可能的陷阱。本文总结了8个关于智......
  • C++ Qt开发:ToolBar与MenuBar菜单组件
    Qt是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍ToolBar工具栏组件以及与之类似的MenuBar菜单栏组件的常用方法及灵活运用。1.1QToolBar工具栏......
  • C++基础 -8- 函数重载
    ———————函数重载———————......
  • c++: 迭代器失效
    一、序列式容器序列式容器(如vector,deque)的迭代器删除正确的做法如下:1//在这里想把等于2的元素都删除2for(autoit=q.begin();it!=q.end();)3{4if(*it==2)5{6it=q.erase(it);//这里会返回指向下一个元素的迭代器,因此不需要再自加了7......
  • Linux下自动生成c++工程的UML类图
    在Qtcreator上面折腾了一两天,也没能生成出UML类图。下面是在Linux通过两个工具Graphviz+Doxygen生成类图的过程。安装软件:sudoaptinstallgraphvizdoxygen进入项目文件目录,首先生成配置文件:doxygen-gDoxygen.config然后编辑该配置文件,修改几个选项:EXTRACT_AL......
  • C++读取FY卫星遥感图像(HDF格式)
    转一下我自己的博客网上找了大概2周,艰难的实现了C++读取HDF图像,CSDN吃相真难看,好多文章都要会员。。。#include<cstdint>#include<hdf5.h>#include<iostream>#include<matplotlibcpp.h>#include<opencv2/opencv.hpp>#include<opencv2/core/core.hpp>#include<......
  • c++ 学习
     c++中常用的class:在C++中,有一些常用的标准库类和一些常见的自定义类,它们提供了各种功能,从容器和算法到文件处理和输入/输出。以下是一些在C++中常用的类:###标准库类:1.**std::string:**-用于处理字符串的类,提供了许多字符串操作的方法。2.**std::vector:**-动态......
  • ffmpeg 添加自定义编解码插件
    有两种方法:一.ffmpeg添加自定义编解码插件(以修改ffmpeg源码的方式添加)例:添加一个解码器,给这个解码器取个名字叫mydecoder,可以通过下面的步骤添加:1.在libavcodec目录下,新建文件mydecoder.c#include"avcodec.h"#include"codec_internal.h"//自己封装的编解码器的头文件#......
  • c++11 乱模版
    std::is_same,std::enable_if,std::is_integraltemplate<typenameT>boolisZero(Tv){if(std::is_same<T,float>::value){return(fabs(v)<FLT_EPSILON);}elseif(std::is_same<T,double>::value){......
  • windows C++
    https://en.cppreference.com/w/cpp/string/basic_stringstd::basic_string C++ Stringslibrary std::basic_string Definedinheader <string>  template<   class CharT,   class Traits = std::char_traits<CharT>,   class......