首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

[C++] 智能指针 进阶

  • 25-04-24 07:41
  • 4449
  • 7427
blog.csdn.net

标题:[C++] 智能指针 进阶
水墨不写bug

在这里插入图片描述


在很久之前我们探讨了智能指针的浅显认识,接下来会更加深入,从源码角度认识智能指针,从而了解智能指针的设计原理,并应用到以后的工作项目中。

本文将会按照C++智能指针的发展历史,回顾智能指针的各个版本的设计。后半部分将会模拟实现最常考的shared_ptr的功能。


一、C++智能指针的发展历程

1. C++98时代:auto_ptr的尝试与缺陷

背景:C++早期依赖手动new/delete,稍微有管理不当比如忘记释放,或者有异常抛出(退出调用的函数栈,但是堆区的指针却找不到了),就可能导致内存泄漏。C++98引入auto_ptr,首次尝试自动化资源管理。
机制:基于RAII(资源获取即初始化),在构造时获取内存,在析构时自动释放内存。
问题:

  • 隐式所有权转移:复制auto_ptr时,原指针变为nullptr,导致难以追踪的悬空指针。
  • 不兼容容器:因拷贝语义异常,无法安全用于STL容器。

示例:

auto_ptr<int> p1(new int(32));
auto_ptr<int> p2 = p1; // p1变为nullptr,后续使用p1导致未定义行为
  • 1
  • 2

结局:最终C++11弃用,C++17移除。因此为了代码的逻辑性和健壮性,以及可移植性,非常不建议使用auto_ptr。


2. Boost库的智能指针

背景:C++社区通过Boost库探索更健壮的解决方案,后来这些方案被C++委员会收录到了C++11。
关键类型:

  • scoped_ptr:禁止拷贝,严格独占所有权,轻量且安全。
  • shared_ptr:引用计数实现共享所有权,解决多所有者场景。
  • weak_ptr:打破shared_ptr循环引用,防止内存泄漏。

影响:直接为C++11智能指针奠定基础。


3. C++11:C++划时代的进步

核心类型:

  • unique_ptr:取代auto_ptr,独占所有权,支持移动语义,禁止拷贝,可管理数组(unique_ptr)。
    unique_ptr<int> p1(new int(10));
    unique_ptr<int> p2 = std::move(p1); // 显式所有权转移
    
    • 1
    • 2
  • shared_ptr:引用计数共享资源,线程安全但性能有开销。
    shared_ptr<A> a = make_shared<A>();
    shared_ptr<A> b = a; // 引用计数增至2
    
    • 1
    • 2
  • weak_ptr:可通过其获取对应的shared_ptr资源,不增加计数,需通过lock()获取临时shared_ptr。
    weak_ptr<A> w = a;
    if (shared_ptr<A> tmp = w.lock()) { /* 使用tmp */ }
    
    • 1
    • 2

改进:

  • 弃用auto_ptr,推荐unique_ptr。
  • 引入make_shared:合并控制块与对象内存分配,提升性能与异常安全。

4. C++14:完善与便利性增强

  • make_unique:填补make_shared的对称性,安全构造unique_ptr。
    auto p = make_unique<int>(20); // 避免显式new
    
    • 1
  • shared_ptr增强:支持自定义删除器与分配器,更灵活的资源管理。

后期的C++17用法不多常见,在此就不再赘述了。

二、智能指针的模拟实现

1、unique_ptr


template<class T>
class UniquePtr
{
    UniquePtr<T>& operator=(const UniquePtr<T>&) = delete;//删除拷贝构造和赋值重载
    UniquePtr(const UniquePtr<T>&) = delete;//这是unique_ptr的标志性的特点
public:
    UniquePtr(T* ptr)
        :_ptr(ptr)//浅拷贝
        //这就要求我们需要在外部new出堆区的空间,然后传递给智能指针来管理
    {}
    ~UniquePtr()
    {
        if(_ptr)//析构
            delete _ptr;
    }
    T& operator*()//重载*和->让智能指针(类)像普通指针(自定义类型)一样使用
    {
        return *_ptr;
    }
    T* operator->()
    {
        return ptr;
    }
private:
    T* _ptr;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

2、shared_ptr


template<class T>
class SharedPtr
{
public:
    SharedPtr(T* ptr)
        :_ptr(ptr)//要求从外部传一个指向堆区的指针
        ,_refcount(new int{1})//开辟在堆上,便于所有的管理同一资源的智能指针对象维护
        ,_pmtx(new std::mutex)//同样的原因
    {}

    SharedPtr(const SharedPtr<T>& obj)
        :_ptr(obj._ptr)//只需要浅拷贝,然后引用计数++
        ,_refcount(obj._refcount)
        ,_pmtx(obj._pmtx)
    {
        AddRef();
    }

    SharedPtr<T>& operator=(const SharedPtr<T>& obj)
    {
        if(obj._ptr != _ptr)//不能给自身赋值
        {
            Release();//释放掉被赋值的智能指针对象的原有资源
            //浅拷贝
            _ptr = obj._ptr;//两个指针指向同一个T*对象
            _refcount = obj._refcount;//两个指针指向同一个int*
            _pmtx = obj._pmtx;//两个指针指向同一个mutex*的锁
            AddRef();
        }
    }
    void AddRef()
    {//增加引用计数需要加锁
        _pmtx->lock();
        (*_refcount)++;
        _pmtx->unlock();
    }

    void Release()
    {
        _pmtx->lock();
        bool f = false;
        if(--(*_refcount) == 0 && _ptr)
        {
            f = true;
            delete _ptr;
            delete _refcount;
        }
        _pmtx->unlock();
        //判断是否资源已经被释放,资源已经被释放,则释放锁
        if(f == true)
        {
            delete _pmtx;
        }
    }
    ~SharedPtr()
    {
        Release();
    }
    int UseCount()
    {
        return *_refcount;
    }
    T& operator*()//重载运算符
    {
        return *_ptr;
    }
    T* operator->()
    {
        return _ptr;
    }
    T* GetPtr()
    {
        return _ptr;
    }
private:
    T* _ptr;//指向堆区资源的裸指针
    int* _refcount;//开辟在堆区的引用计数
    std::mutex* _pmtx;//堆区的锁,考虑线程安全
    //如果设置在栈上,那么每一个对象都有一个独立的引用计数
    //每一次自增自减都需要对同一引用计数的所有对象维护,非常难以维护
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82

3、weak_ptr

库中的wear_ptr的实现需要结合起来shared_ptr,shared_ptr内部含有两个引用计数,一个是记录管理资源的shared_ptr(占用引用计数)的个数,一个记录指向资源的weak_ptr(不占用引用计数)的个数。
在这里,为了简便而言,我们实现一个简化版本的weak_ptr,对上面的知识理解即可。


// 简化版本的weak_ptr实现
template<class T>
class WeakPtr
{
public:
    WeakPtr()
        :_ptr(nullptr)
    {}

    WeakPtr(const SharedPtr<T>& sp)
        :_ptr(sp.get())
    {}

    WeakPtr<T>& operator=(const SharedPtr<T>& sp)
    {
        _ptr = sp.get();
        return *this;
    }
    T& operator*()
    {
        return *_ptr;
    }
    T* operator->()
    {
        return _ptr;
    }
private:
    T* _ptr;
};

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

~完
转载请注明出处

在这里插入图片描述

注:本文转载自blog.csdn.net的水墨不写bug的文章"https://blog.csdn.net/2301_79465388/article/details/146674213"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

107
Java
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2024 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top