首页 > 其他分享 >CPP 智能指针

CPP 智能指针

时间:2024-11-16 23:07:09浏览次数:1  
标签:cnt obj 智能 other CPP shared ref ptr 指针

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 copying

AutoPtr4(AutoPtr4&& ptr4) noexcept // move constructor
    : ptr(ptr4)
{
    ptr4.ptr = nullptr;
}

AutoPtr4& operator=(const AutoPtr4& ptr4) = delete; // disable copy assignment

AutoPtr4& 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 constructor
    shared_ptr(const shared_ptr &other) : obj_(other.obj_), ref_cnt_(other.ref_cnt_)
    {
        this->ref_cnt_->add_shared_cnt();
    }

    // copy assignment operator
    shared_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 constructor
    shared_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 operator
    shared_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();
}

标签:cnt,obj,智能,other,CPP,shared,ref,ptr,指针
From: https://www.cnblogs.com/dutrmp19/p/18550109

相关文章

  • springboot毕设 面向社区的洗衣店智能服务系统设计与实现808ub程序+论文
    本系统(程序+源码)带文档lw万字以上文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着城市化进程的加快,社区居民对于生活服务的便捷性和智能化需求日益增长。洗衣作为日常生活中的一项重要服务,传统的洗衣店模式已难以满足现代人追求......
  • 算法沉淀一:双指针
    目录前言:双指针介绍对撞指针快慢指针题目练习1.移动零2.复写零3.快乐数4.盛水最多的容器5.有效三角形的个数6.和为s的两个数7.三数之和8.四数之和前言:此章节介绍一些算法,主要从leetcode上的题来讲解,讲解内容为做题思路,附加代码。欢迎与我大家一起学习共同进......
  • 智能体探秘数据宝库:数据库驱动的智能决策之旅
    一、数据利用数据仓库作为数据源:数据仓库是一个大型的、面向主题的、集成的、非易失的、反映历史变化的数据集合,用于支持管理决策。它存储了大量的结构化数据,这些数据是智能体进行学习和决策的重要基础。智能体可以通过访问数据仓库,获取所需的数据来训练模型、进行预测和决......
  • AI 写作(九)实战项目二:智能新闻报道(9/10)
    一、项目概述在当今信息爆炸的时代,新闻传播行业正面临着前所未有的挑战与机遇。随着科技的飞速发展,人们获取信息的渠道日益多样化,对新闻的时效性、准确性和个性化需求也不断提高。在这样的背景下,AI写作在智能新闻报道中的重要性愈发凸显。AI写作能够极大地提高新闻报道的效......
  • 基于Spring Boot成人自考本科教育网站设计与实现(源码+定制+讲解)在线自考教育管理系统
    博主介绍:  ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W+粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台的优质作者。通过长期分享和实战指导,我致力于帮助更多学生......
  • 使用Python实现智能食品安全监测的深度学习模型
    食品安全是关乎公共健康的重要议题。随着科技的发展,深度学习技术在食品安全监测中的应用越来越广泛,通过自动化和智能化手段,可以有效提高食品质量检测的效率和准确性。本文将介绍如何使用Python实现一个智能食品安全监测的深度学习模型,并通过代码示例展示实现过程。项目概述......
  • GC优化:栈内存、span、NativeMemory、指针、池化内存 笔记
    stackalloc使用栈内存,减少GC压力varwordMatchCounts=stackallocfloat[wordCount];SpanSpan支持reinterpret_cast的理念,即可以将Span强制转换为SpanSpan支持reinterpret_cast的理念,即可以将Span强制转换为Span(其中,Span中的索引0映射到Span的前四个字节......
  • [C++] 智能指针
    文章目录智能指针的使用原因及场景分析为什么需要智能指针?异常抛出导致的资源泄漏问题分析智能指针与RAIIC++常用智能指针使用智能指针优化代码优化后的代码优化点分析析构函数中的异常问题解决方法RAII和智能指针的设计思路详解什么是RAII?RAII的工作原理智能......
  • 26. 智能指针
    一、什么是智能指针  当我们使用new关键字为指针变量动态申请内存时,但是使用完毕之后,我们可能会忘记使用delete关键字手动回收内存。因此,C++中提供了智能指针。当智能指针过期时,其析构函数将使用delete来释放内存。因此,如果将new返回的地址赋给智能指针对象,将无......
  • 【技术革新】哋它亢编程语言3.12版本:智能时代的新里程碑
    在技术的浪潮中,总有一些时刻标志着新时代的开始。今天,我们要探讨的“哋它亢编程语言”3.12版本,就是这样一个时刻。这个版本不仅带来了性能的飞跃,还引入了多项创新特性,为开发者提供了更广阔的舞台。3.12版本的亮点特性:性能的全面提升:哋它亢3.12版本在性能上进行了深度优化,无论......