C/C++面试:手写智能指针类

2023-05-16

shared_ptr原理

shared_ptr实际上是对裸指针进行了一层封装,成员变量除了裸指针之外,还有一个引用计数,它记录裸指针被引用的次数(有多少个shared_ptr指向这同一个裸指针),当引用计数为0时,自动释放裸指针指向的资源。影响引用次数的场景包括:构造、赋值、析构。基于三个最简单的场景,实现一个demo版shared_ptr如下(实现既不严谨也不安全,仅用于阐述原理):

//智能指针的实现
 
#include<iostream>
using namespace std;
#include<memory>
 
template<class T>
class MyShared_ptr
{
public:
 
	//构造函数
	explicit MyShared_ptr(T *p = NULL)
	{
		this->m_ptr = p;
		this->m_count = new size_t;
		if (p == NULL)
		{
			*this->m_count = 0;
		}
		else
		{
			*this->m_count = 1;
		}
	}
 
	//析构函数
	~MyShared_ptr()
	{
		if (this->m_ptr)
		{
			if (*(--this->m_count) == 0)
			{
				delete this->m_ptr;
				delete this->m_count;
				this->m_ptr = NULL;
				this->m_count = NULL;
			}
		}
	}
 
	//拷贝构造函数
	MyShared_ptr(const MyShared_ptr& shared)
	{
		if (this != &shared)
		{
			this->m_ptr = shared.m_ptr;
			this->m_count = shared.m_count;
			(*this->m_count)++;
		}
	}
 
	//重载赋值操作符
	MyShared_ptr& operator=(const MyShared_ptr& shared)
	{
		if (this->m_ptr == shared.m_ptr)
		{
			return *this;
		}
		if (this->m_ptr)
		{
			if (*(--this->m_count) == 0)
			{
				delete this->m_ptr;
				delete this->m_count;
				this->m_ptr = NULL;
				this->m_count = NULL;
			}
		}
		this->m_ptr = shared.m_ptr;
		this->m_count = shared.m_count;
		(*this->m_count)++;
		return *this;
	}
 
    //重载->操作符
	T& operator->()
	{
		if (this->m_ptr)
		{
			return this->m_ptr;
		}
	}
 
    //重载 *
	T& operator*()
	{
		if (this->m_ptr)
		{
			return *(this->m_ptr)}
	}
 
    //实现 use_count函数
	size_t use_count()
	{
		return *this->m_count;
	}
 
 
 
private:
	T *m_ptr;  //内部指针,保证拷贝指向同一内存
	size_t *m_count;  //为了保证指针的引用计数,这里我是用了指针来做
};

weak_ptr的原理。

weak_ptr又叫做弱指针,它是用来解决shared_ptr循环引用的问题。为啥叫弱呢?shared_ptr A被赋值给shared_ptr B时,A的引用计数加1,;shared_ptr A被赋值给weak_ptr C时,A的引用计数不变。

weak_ptr在使用时,是与shared_ptr绑定的。基于SharedPtr实现来实现demo版的WeakPtr,并解决循环引用的问题,全部代码如下:

template<typename T>
class SharedPtr {
public:
    int* counter;
    int* weakref;
    T* resource;

    SharedPtr(T* resc = nullptr) {
        cout << __PRETTY_FUNCTION__ << endl;
        counter = new int(1);
        weakref = new int(0);
        resource = resc;
    }

    SharedPtr(const SharedPtr& rhs) {
        cout << __PRETTY_FUNCTION__ << endl;
        resource = rhs.resource;
        counter = rhs.counter;
        ++*counter;
    }

    SharedPtr& operator=(const SharedPtr& rhs) {
        cout << __PRETTY_FUNCTION__ << endl;
        --*counter;
        if (*counter == 0) {
            delete resource;
        }

        resource = rhs.resource;
        counter = rhs.counter;
        ++*counter;
    }

    ~SharedPtr() {
        cout << __PRETTY_FUNCTION__ << endl;
        --*counter;
        if (*counter == 0) {
            delete counter;
            delete resource;
        }
    }

    int use_count() {
        return *counter;
    }
};

template<typename T>
class WeakPtr {
public:
    T* resource;

    WeakPtr(T* resc = nullptr) {
        cout << __PRETTY_FUNCTION__ << endl;
        resource = resc;
    }

    WeakPtr& operator=(SharedPtr<T>& ptr) {
        cout << __PRETTY_FUNCTION__ << endl;
        resource = ptr.resource;
        ++*ptr.weakref;  // 赋值时引用计数counter不变,改变弱引用计数weakref
    }

    ~WeakPtr() {
        cout << __PRETTY_FUNCTION__ << endl;
    }
};

unique_ptr

template<typename T>
class PointerDeleter{
public:
    void operator() (const T *_ptr){
        if(_ptr){
            delete _ptr;
            _ptr = nullptr;
        }
    }
};

template<typename T, typename Delete = PointerDeleter<T>>
class UniquePtr{
private:
    T *_ptr;
public:
    // -----------------------------
    explicit UniquePtr(T *ptr = nullptr) : _ptr(ptr){}
    
    ~UniquePtr(){
        if(_ptr){
            delete _ptr;
            _ptr = nullptr;
        }
    }

    //---------------------------------------------
    // non-copyable
    UniquePtr(const UniquePtr & p) = delete ;
    UniquePtr & operator = (const UniquePtr & p) = delete ;

    // move constructor
    UniquePtr(UniquePtr && p) : _ptr(p._ptr){
        p._ptr = nullptr;
    }

    // move assignment
    UniquePtr& operator=(UniquePtr && p) noexcept {
        std::swap(this->_ptr, p._ptr);
        return *this;
    }
    
    //---------------------------------------
    
    T & operator*(){
        return *(this->_ptr);
    }
    
    T *operator->(){
        return this->_ptr;
    }
    
    operator bool (){
        return this->_ptr;
    }
    
    T *get() const {
        return this->_ptr;
    }
    
    T *release(){
        T *pointer = this->_ptr;
        this->_ptr = nullptr;
        return pointer;
    }

    void reset (T *ptr) {
        UniquePtr<T, Delete>().swap(*this);
        this->_ptr = ptr;
    }

    void swap(UniquePtr &p) {
        std::swap(this->_ptr, p._ptr);
    }
};
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C/C++面试:手写智能指针类 的相关文章

  • 基于TCP/IP和UDP协议的socket编程结构解析

    1 套接字 xff08 socket xff09 socket起源于Unix xff0c 而Unix Linux基本哲学之一就是 一切皆文件 xff0c 都可以用 打开open gt 读写write read gt 关闭close 模式来操
  • printf 函数实现的深入剖析[转载]

    研究printf的实现 xff0c 首先来看看printf函数的函数体 xff01 int printf const char fmt int i char buf 256 va list arg 61 va list char amp f
  • Altium Designer(AD20)画PCB时ctrl键、shift键、鼠标按键的妙用

    ctrl键的妙用 1 绘画窗口放大缩小 按住ctrl键 43 滚动鼠标滚轮 xff0c 滚前放大 xff0c 滚后缩小 2 高亮 按住ctrl键 43 鼠标点击有网络信号的焊盘 过孔 线 xff0c 便高亮该网络 xff0c 其他网络变暗或
  • PyQt结合Opencv显示图片以及摄像头

    环境 xff1a python3 7 PyQt5 11 3 OpenCV python4 0 0 21 Pycharm 2018 2 2 1 通过PyQt与OpenCV显示图片 import sys import cv2 import nu
  • allegro更新铜皮方法和快捷键

    前景 xff1a 在如今时代 xff0c allegro软件是三大PCB设计软件之一 xff0c 不少知名公司都要求会allegro软件 xff0c 所以很多PCBlayout工程师开始转用allegro xff0c 同时也出现很多新手学a
  • Allegro快捷键(env)位置和快捷键设置

    前景 在画PCB板 xff0c 保证质量同时 xff0c 也要讲究效率 xff0c 要是一只手用鼠标来点选命令画板 xff0c 效率会大大折扣 xff0c 所以出现PCBlayout快捷键 xff0c 本文章将的是allegro快捷键 al
  • Altium Designer使用者,你想要一键出Gerber吗?

    前言 在我们辛辛苦苦画完一个PCB板 xff0c 细心谨慎地生成Gerber xff0c 突然 xff0c 发现一个丝印没摆好 xff0c 只能改丝印再重新生成Gerber xff0c 又突然 xff0c 发现有根线离电源太近了 xff0c
  • allegro同比例放大缩小LOGO丝印

    前言 在遇到元件密集情况下 xff0c 既要兼顾元件位号丝印 xff0c 又能凸显公司的LOGO时 xff0c 常常碰到LOGO丝印太大 xff0c 放不下 xff0c 要是再缩小一点 xff0c 就能放下了 所以我就写了这篇文章 xff0
  • 利用Sigrity的SPEED2000进行时域电源噪声分析

    前序 相信大家在网上可以找到本文章的类似教程 xff0c 我就是这样 xff0c 找到了教程 xff0c 兴致冲冲地按教程每个步骤操作 xff0c 但最后因为素材不一样 xff0c 得不到想要的结果 xff0c 有时出来的波形是一条水平线
  • 利用Sigrity PowerDC进行单板直流仿真--静态功率传输体系分析

    前序 本文章利用Sigrity PowerDC进行单板直流仿真 静态功率传输体系分析的教程写出来 xff0c 同时 xff0c 将Sigrity PowerDC 单板直流仿真分析素材上传 xff0c 供大家使用 xff0c 不用苦苦寻找仿真
  • org.htmlparser小结

    org htmlparser 主要用来解析HTML网页 一 基本上HTML中的每个标签对应于一个类 xff0c 例如 xff1a p标签对应于ParagraphTag类 ul标签对应于BulletList类 li标签对应于Bullet类 a
  • STM32中使用printf打印串口数据

    STM32使用printf打印串口 摘要 该方法适用于 STM32 xff0c 实现了使用 printf 等标准 C 流函数输出数据的办法 xff0c 极大的减少了输出串口数据时所需要做的数据处理 实现原理 在 C 库中 xff0c pri
  • 尺取法(图文解析、初学推荐)

    文章目录 最少连续页 xff08 poj3320 xff09 分析题意第一步 xff1a 找第一个满足条件区间第二步 xff1a 开始将左端边界向右移 xff0c 达到 缩小 区间 减少连续页的目的 归纳总结代码 尺取法 xff1a 顾名思
  • 第九届蓝桥杯——倍数问题(数论、枚举)

    倍数问题 众所周知 xff0c 小葱同学擅长计算 xff0c 尤其擅长计算一个数是否是另外一个数的倍数 但小葱 只擅长两个数的情况 xff0c 当有很多个数之后就会比较苦恼 现在小葱给了你 n 个数 xff0c 希望你 从这 n 个数中找到
  • 基于Python OpenCV的车牌识别(一)————车牌定位

    一开始本想基于OpenCV原理编写定位程序的 xff0c 但发现效果并不是特别理想 xff0c 只能识别我处理的那张图片的车牌 xff0c 在使用其他图片识别的时候失误非常多 xff0c 几乎识别不到车牌 xff0c 下面附上识别的代码和效
  • 计算机网络——尝试SMTP交互(邮件发送)

    前言 本文通过 Windows 命令提示符 xff08 cmd xff09 实现邮件发送 第一步 xff1a 打开 Windows Telnet Client 功能 打开控制面板 点击程序 点击启动或关闭 Windows 功能 将 Teln
  • 离散数学:推理规则

    推理规则解释说明前提引入规则可以在证明的任何时候引入前提结论引入规则在证明的任何时候 xff0c 已证明的结论都可以作为后续证明的前提置换规则在证明的任何时候 xff0c 命题公式中的任何子命题公式都可以用与之等价的命题公式置换假言推理规则
  • 离散数学:谓词逻辑命题符号化

    个体词 个体常项或个体常元 xff1a 使用 x y z 表示个体变项或个体变元 xff1a 使用 a b c 表示个体域或论域 xff1a 个体变元的取值全总个体域 xff1a 宇宙件一切事物 谓词 概念 xff1a 表示个体性质或彼此之
  • 离散数学:主范式(主析取范式、主合取范式)

    求解主析取范式 主合取范式方法 1 真值表法 在表中列出变元值的全部可能 查表判断命题 命题结果真 xff0c 变元值对应主析取范式 命题结果假 xff0c 变元值对应主合取范式 2 等值演算法 命题化简 蕴涵等值式 xff1a A B A

随机推荐

  • Camera:双摄基本原理

    基本概念 基线 xff1a 两镜头的间距 景深 xff1a 画面清晰范围 xff0c 景深小 浅 背景虚化 xff0c 景深大背景清晰 影响景深的三个因素 xff1a 光圈 xff08 反比 xff0c 光圈越大景深越小 xff09 焦距
  • Linux:Hello World 模块

    前言 Linux 系统为应用程序提供了功能强大且容易扩展的 API xff0c 但在某些情况下 xff0c 这还远远不够 与硬件交互或进行需要访问系统中特权信息的操作时 xff0c 就需要一个内核模块 下面从 Hello World 模块来
  • 基础算法题 —— 计算字符串的编辑距离(动态规划)

    题解 在题目所求的编辑距离是指字符串 a 转换成字符串 b 所需最小的操作步骤 a i 61 b j 时 xff0c 要使 a i 61 61 b j 可使用的操作步骤如下 xff1a a i 可替换成 b j 字符串 a 下标为 i 的位
  • Matlab —— 02 基本操作与矩阵输入

    一 基本操作 1 help 功能 xff1a 便于快速了解指令的使用 ex 查询 pi 的简明介绍 Question 通过 matlab 计算出下列算式结果 Answer 1 2 或 xff08 3 xff09 xff08 4 xff09
  • Matlab —— 03结构化程式与自定义函数

    Script writing 新建脚本编辑界面 编辑测试文档 运行节 将整个框架划分为多个小节运行 xff0c 便于进行 Debug 设置断点 检查变量数值 方法一 xff1a 工作区内检查 方法二 xff1a 鼠标滑到变量位置 Struc
  • [unity] NavMesh 寻路 贴边走的问题 优化。

    NavMesh 寻路出来后 xff0c 角色走路很多时候贴着地图的边缘走 xff0c 很别扭 网上找了一个类似的问题 xff1a http www manew com thread 94163 1 1 html 里面方案 也挺适合我们的情况
  • 网易云ncm文件转mp3

    本人卖了一个ipod nano6 xff0c 帮买家导些歌 xff0c 结果用网易云下下来一堆ncm文件 xff0c 一脸懵逼 xff0c 因为ipod只能放mp3文件 上网查了一下ncm文件 xff0c 只能在会员有效期内放这个歌 于是上
  • catkin_make编译时fatal error: ###_msgs/***.h: 没有那个文件或目录

    h是头文件 xff0c 头文件 xff0c 就是一些定义和声明 xff0c 注意是定义 xff08 算是API接口吧 xff09 xff0c 编译时先加载这些头文件 xff0c 加载好了后主程序才能调用这些定义 那出现这种错误就是编译该程序
  • Theta* : 基于网格的任意角度寻路

    原文地址 xff08 科学上网 xff09 xff1a https arxiv org ftp arxiv papers 1401 1401 3843 pdf 1 简介 在本文中 xff0c 我们将研究一种机器人技术或视频游戏中使用的路径规
  • deepsort之YOLO系列目标跟踪及其他功能

    文章目录 一 ID switch是什么 xff1f 二 deepsort框架二 deepsort需要的模型1 目标检测器2 目标跟踪器 一 ID switch是什么 xff1f 跟踪问题中最重要的就是数据关联 xff08 data asso
  • PX4软件在环仿真注意点

    注 xff1a 最新内容参考PX4 user guide 点击此处 PX4下载指定版本代码和刷固件的三种方式 点击此处 PX4sitl固件编译方法 点击此处 PX4开发指南 点击此处 PX4无人机仿真 Gazebo 点击此处 px4仿真 知
  • cmake:生成动态链接库并使用

    已知 库函数的源文件名字叫hello c xff0c 库函数的头文件名字叫hello h xff0c 生成的动态链接库函数的名称叫libhello so xff0c 目标是在 hello install文件夹下安装这个库 xff0c 以便后
  • 算法:皇后问题

    问题 国际象棋中的皇后 xff0c 可以横向 纵向 斜向移动 如何在一个NXN的棋盘上放置N个皇后 xff0c 使得任意两个皇后都不在同一条横线 竖线 斜线方向上 xff1f 举个栗子 xff0c 下图的绿色格子是一个皇后在棋盘上的 封锁范
  • OpenCV+Python二维码条形码识别

    先上源码 xff0c github地址 xff1a https github com DerrickRose25 Opencv QRcode recognition 环境 xff1a Pycharm Python3 7 在pycharm里安
  • Onvif协议:实现Probe命令来进行设备发现(discover)

    在onvif协议对接中 xff0c 首先要明确服务器和客户端的身份 服务器 xff1a 通常是你要对接的其他厂家的数字摄像头 xff08 IPC xff09 客户端 xff1a 通常是对接的ipc的设备程序 xff0c 安防业内多称 xff
  • Linux C/C++编程:Udp组播(多播)

    Udp多播简介 概叙 单播用于两个主机之间单对单的通信广播用于一个主机对整个局域网上所有主机上的数据通信单播和广播是两个极端 xff0c 要么对一个主机进行通信 xff0c 要么对整个局域网的主机进行通信实际情况下 xff0c 经常需要对一
  • cmake:同一目录下多个源文件

    此文为 xff1a 轻松入门cmake系列教程前文为 xff1a cmake xff1a Hello cmake 接下来进入稍微复杂的例子 xff1a 在同一个目录下有多个源文件 第一个实验 实践 在之前的目录下添加2个文件 xff0c t
  • cmake:string

    字符串操作 概要 Search span class token operator and span Replace span class token function string span span class token punctu
  • 性能:你知道并发用户数应该怎么算吗

    我们知道 xff0c 一个性能测试中 xff0c 往往会有各种各样的指标 xff0c 比如TPS RPS QPS HPS CPM等 我们在实际工作的时候 xff0c 应该对这些概念有统一的认识 建议使用TPS作为关键的性能指标 另外 xff
  • C/C++面试:手写智能指针类

    shared ptr原理 shared ptr实际上是对裸指针进行了一层封装 xff0c 成员变量除了裸指针之外 xff0c 还有一个引用计数 xff0c 它记录裸指针被引用的次数 xff08 有多少个shared ptr指向这同一个裸指针