CPP 智能指针

news/2024/11/16 23:20:55/文章来源:https://www.cnblogs.com/dutrmp19/p/18550109

CPP 智能指针

  • Created: 2024-06-30T20:43+08:00
  • Published: 2024-11-16T23:17+08:00
  • Categories: C-CPP

智能指针的作用

智能指针最初使的作用就是离开作用域调用析构函数。
因为 malloc 出来的东西只能通过指针持有,栈上的对象在离开作用域后会自动调用析构函数,但是裸指针会不调用持有对象的析构函数。

智能指针的知识要点有:

  1. unique_ptr 要禁用 copy constructor, copy assignment operator
  2. shared_ptr 需要实现 big five,在 move constructor 和 move assignment operator 中要将右值重置
  3. 通过 weak_ptr 防止循环引用,原理是引用计数块中及统计 shared_count,也统计 weak_count,
    shared_count=0 时候释放资源,当 weak_count=0 时候释放引用计数块
  4. std::make_shared 实现有 std::forward,要会写
  5. std::make_shared 会把引用计数块和资源块放到同一块内存区域中以加快访问速度
  6. 要小心 shared_ptr{T* obj},可能导致两个 shared_ptr 管理同一份资源,会 double free

unique_ptr

从中可以看到,unique_ptr 禁用了拷贝构造和赋值运算符,仅仅实现了移动构造和移动赋值构造,这也就使得它是独占式的。

C++内存管理——unique_ptr - 知乎
C++ 智能指针详解(一)——unique_ptr - 知乎

AutoPtr4(const AutoPtr4& ptr4) = delete; // disable copyingAutoPtr4(AutoPtr4&& ptr4) noexcept // move constructor: ptr(ptr4)
{ptr4.ptr = nullptr;
}AutoPtr4& operator=(const AutoPtr4& ptr4) = delete; // disable copy assignmentAutoPtr4& operator=(AutoPtr4&& ptr4) noexcept // move assignment
{if(this == &ptr4){return *this;}delete this->ptr;this->ptr = ptr4.ptr;ptr4.ptr = nullptr;return *this;
}

shared_ptr

C++ 智能指针详解(二)——shared_ptr 与 weak_ptr - 知乎

shared-ptr-memory

shared_ptr 的引用计数通过 _Rep 指向的控制块控制,相关的操作在基类 _Ref_count_base 中已经实现,主要就是:
当 _Uses 为 0 时,调用 _Destroy() 释放原生对象内存;
当 _Weaks 为 0 时,调用 _Delete_this() 释放控制块自己的内存
(注意:只有当弱引用计数为 0 时,控制块的内存才会被所释放,如果有 weak_ptr 弱引用指针存在,控制块内存不会释放,这一点后面介绍),其余还有引用计数的增加和减少等函数。

  1. shared_ptr 内存结构 / 共享指针实现原理 / 引用计数开辟的空间是一个什么结构
  2. 如何破除循环引用以及原理 / 为什么不会增加引用计数 / 弱指针如何实现的:内存模型完全一致,只有类型和 api 的区别
  3. 不要用裸指针构造 shared_ptr / T 继承 enable_share_from_this 解决指针构造 shared_ptr
  4. 引用计数如何实现线程安全:使用了 atomic,参考:
    1. atomic 实现原理 - 知乎
    2. atomic 的底层实现 - 王的博客 - 博客园
    3. 锁 bus,exchange 原子操作,LR/SC,CAS

禁用的函数合运算符有哪些,他们的运算符重载具体如何实现的。

拷贝构造函数和赋值运算符分别在什么场景下使用。让你实现对应的重载具体代码要包含哪些内容

手写简单的 shared_ptr

参考 ./shared_ptr.cpp

#include <atomic>
#include <iostream>
#include <utility>
using std::atomic;struct RefCnt
{atomic<size_t> shared_cnt{0};atomic<size_t> weak_cnt{0};void add_shared_cnt() { shared_cnt.fetch_add(1); }void sub_shared_cnt() { shared_cnt.fetch_sub(1); }
};template <typename T>
struct shared_ptr
{T *obj_{nullptr};RefCnt *ref_cnt_{nullptr};shared_ptr(T *obj) : obj_(obj){this->ref_cnt_ = new RefCnt();this->ref_cnt_->add_shared_cnt();}shared_ptr(T *obj, RefCnt *ref_cnt) : obj_(obj), ref_cnt_(ref_cnt) {}void try_release(){if (this->ref_cnt_->shared_cnt == 0){delete this->obj_;delete this->ref_cnt_;}}~shared_ptr(){std::cout << "~shared_ptr()" << std::endl;if (this->ref_cnt_){this->ref_cnt_->sub_shared_cnt();try_release();}}T *operator->() const{return this->obj_;}// copy constructorshared_ptr(const shared_ptr &other) : obj_(other.obj_), ref_cnt_(other.ref_cnt_){this->ref_cnt_->add_shared_cnt();}// copy assignment operatorshared_ptr &operator=(const shared_ptr &other){this->obj_ = other.obj_;this->ref_cnt_ = other.ref_cnt_;this->ref_cnt_->add_shared_cnt();return *this;}// move constructorshared_ptr(shared_ptr &&other){std::cout << "shared_ptr(shared_ptr &&other)" << std::endl;this->obj_ = other.obj_;this->ref_cnt_ = other.ref_cnt_;other.obj_ = nullptr;other.ref_cnt_ = nullptr;}// move assign operatorshared_ptr &operator=(shared_ptr &&other){this->obj_ = other.obj_;this->ref_cnt_ = other.ref_cnt_;other.obj_ = nullptr;other.ref_cnt_ = nullptr;return *this;}
};template <typename T, typename... Args>
shared_ptr<T> make_shared(Args &&...args)
{auto obj = new T(std::forward<Args>(args)...);auto ref_cnt = new RefCnt();ref_cnt->add_shared_cnt();return shared_ptr(obj, ref_cnt);
}
struct Point
{float x_{0}, y_{0};Point(float x, float y) : x_(x), y_(y) {}~Point(){std::cout << "Point::~Point(), x = " << x_ << ", y = " << y_ << std::endl;}void print_self() const{std::cout << "Point: (" << this->x_ << ", " << this->y_ << ")" << std::endl;}
};int main()
{auto p = make_shared<Point>(1, 2);p->print_self();auto p_copy(p);p_copy->print_self();auto p_copy_assignment = p;p_copy_assignment->print_self();auto p_move(std::move(p));p_move->print_self();auto p_move_assignment = std::move(p_copy);p_move_assignment->print_self();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/834831.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

先天软工圣体队——冲刺日记(第三天)

1. 每位团队成员的分工与进度成员 完成的任务 完成的任务时长 剩余时间何愉心、邱雨涵 对以及会议进行记录与vlog剪辑 3小时 1小时陈思雨,郑奇键 添加资料库滑动框,美化UI 2小时 2小时陈尚冰 ”登录“”注册“页面的开发,安全性强化 5小时 2小时柯鸿毅 API拓展功能完善 2小时…

学期2024-2025-1 学号20241306 《计算机基础与程序设计》第8周学习总结

学期2024-2025-1学号20241306 《计算机基础与程序设计》第8周学习总结 作业信息这个作业属于哪个课程 <班级的链接>(如2024-2025-1-计算机基础与程序设计)这个作业要求在哪里 <作业要求的链接>(如2024-2025-1计算机基础与程序设计第8周作业)这个作业的目标 功能设…

第二篇:Scrum冲刺博客

冲刺博客:Day 2 - 启动与规划 站立式会议照片: ![站立式会议 - Day 2](链接到Day 2的照片) 工作进展:许莹柔(机器学习工程师):昨日完成:阅读《构建之法》第六章,为模型训练做准备。 今日计划:开始数据集的预处理工作。 遇到的困难:无。肖晓霞(UI设计师):昨日完成:…

AtCoder Beginner Contest 380

A - 123233 题意给个\(6\)位数,判断是否是\(1\)个\(1\),\(2\)个\(2\),\(3\)个\(3\)。思路模拟。代码点击查看代码 #include <bits/stdc++.h> using namespace std; #define int long long typedef pair<int, int> pii;const int mxn = 1e6 + 5;void solve() {st…

数学分析

CH1 集合与映射 函数的定义?函数的定义必须要由映射引出来 CH2 数列极限 CH3 函数极限与连续函数 CH4 微分 CH5 微分中值定理及其应用 CH6 不定积分 CH7 定积分 CH8 反常积分

Astro搭建个人博客

大家好,我是Yinph。 今天给大家带来一篇关于如何使用Astro快速搭建个人博客的文章。 直接进入正题: 一、准备工作在Astro挑选一个自己心仪的博客模板 安装nodejs 一个GitHub账号,并建一个仓库 一个Cloudflare账号 一个Netlify账号 最好下载VS Code,方便以后修改博客:::note…

【C++复习】栈-下篇

大家好,这里是不会写开场白的Yinph。 今天我们先来复习一下中缀表达式、前缀表达式和后缀表达式,以及如何用栈来实现它们之间的运算。 一、中缀表达式 ‌‌中缀表达式‌是一种算术或逻辑公式的表示方法,其中操作符位于操作数的中间。这种表示方法符合人们的日常书写习惯,因…

gofiber: 模板:判断if条件

一,代码: 1,controller func (dc *ArticleController) GetArticle(c *fiber.Ctx) error {// 处理获取文章的逻辑article := new(Article)article.Id = 1article.Title = "三国演义金圣叹批本"article.Author = "罗贯中"user:=c.Query("user")m…

starrycan的pwn随笔——ELF文件和延迟绑定机制

一.ELF文件结构 0x01什么是ELF文件 1.linux环境中,二进制可持性文件的类型是ELF(Executable and LinkableFormat)文件。类似windows下的exe 2.elf文件的格式比较简单,我们需要了解的就是elf文件中的各个节、段等概念 3.程序elf的基本信息存在于elf的头部信息中,这些信息包括…

达梦数据库DM管理工具如何浏览数据,用条件筛选数据

前言 大家好,我是小徐啊。达梦数据库是我们一款常用的国产数据库,我之前一直在使用它。用起来和mysql和postgresql比起来,还是差不多的。而且它自带了数据库连接工具DM管理工具,使我们很方便的连接它。 今天,小徐就来介绍下如何用DM管理工具浏览数据,并且用条件去筛选数据…

标注图片怎么导出VOC格式和COCO格式

图片怎么标注参考 https://www.cnblogs.com/minseo/p/18549804下载 从github下载代码,或压缩包# git clone https://github.com/LabelMe/labelme转换 示例文件在以下路径# labelme-main\examples\instance_segmentation目录以及各个目录的用途如下打过标签的图片和json文件放以…

vscode Markdown文件如何使代码超出屏幕可视区域不换行

在编写Markdown文件的表格时,单元格内过长的内容会使得行超出可视区域,Markdown处理方式为单行用多行表示,如下图所示:这样会破坏表格的可读性,利用快捷键Alt+Z,可变为如下形式:使得表格每列对齐以增加可读性