• 【C++】鱼的一生, 智能指针的实现


    本节将实现一个名为SmartPointer的简化版本的shared_ptr模板类,相关C++代码如下。

    本文引用自作者编写的下述图书; 本文允许以个人学习、教学等目的引用、讲授或转载,但需要注明原作者"海洋饼干叔
    叔";本文不允许以纸质及电子出版为目的进行抄摘或改编。
    1.《Python编程基础及应用》,陈波,刘慧君,高等教育出版社。免费授课视频 Python编程基础及应用
    2.《Python编程基础及应用实验教程》, 陈波,熊心志,张全和,刘慧君,赵恒军,高等教育出版社Python编程基础及应用实验教程
    3. 《简明C及C++语言教程》,陈波,待出版书稿。免费授课视频

    //Project - SmartPointer
    #include 
    using namespace std;
    
    class Fish {
    public:
        string sName;
        Fish(const string& name){
            sName = name;
            cout << "Fish Constructor called: " << sName << endl;
        }
    
        void sayHello(){
            cout << "Aloha: " << sName << endl;
        }
    
        ~Fish(){
            cout << "Fish Destructor called:  "  << sName << endl;
        }
    };
    
    template <typename T>
    class SmartPointer {
    private:
        T* ptr;             //原始指针
        int* refCount;      //指向引用计数的指针
        void releaseReference(){   //释放对对象的引用
            if (!ptr)
                return;
            (*refCount)--;
            if (*refCount==0){
                delete ptr; ptr = nullptr;
                delete refCount; refCount = nullptr;
            }
        }
    
    public:
        SmartPointer(T* p=nullptr){
            ptr = p;
            refCount = new int;
            *refCount = 1;
        }
    
        ~SmartPointer(){
            releaseReference();
        }
    
        //拷贝构造函数
        SmartPointer(const SmartPointer& r) {
            cout << "Copy constructor of SmartPointer." << endl;
            ptr = r.ptr;
            refCount = r.refCount;
            (*refCount)++;
        }
    
        //重载=操作符
        SmartPointer& operator=(const SmartPointer& r){
            cout << "operator=(const SmartPointer&)." << endl;
            if (&r == this)
                return *this;
            releaseReference();
            ptr = r.ptr;
            refCount = r.refCount;
            (*refCount)++;
            return *this;
        }
    
        //重载*操作符
        T& operator*(){
            cout << "operator*() of SmartPointer." << endl;
            if (ptr)
                return *ptr;
            throw exception();
        }
    
        //重载->操作符
        T* operator->(){
            cout << "operator->() of SmartPointer." << endl;
            if (ptr)
                return ptr;
            throw exception();
        }
    
        //查询引用计数
        int referenceCount(){
            return *refCount;
        }
    };
    
    int main() {
        SmartPointer<Fish> f1(new Fish("Dora"));
        SmartPointer<Fish> f2(new Fish("Tom"));
        auto f3 = f1;      //调用f3的拷贝构造函数,以f1为实参
        f2 = f1;           //调用f2的operator=()函数,以f1为实参,间接导致Tom鱼被释放
        (*f2).sayHello();  //调用f2的operator*()函数
        f2->sayHello();    //调用f2的operator->()函数
        cout << "Refernce count of Dora fish: " << f2.referenceCount() << endl;
        return 0;
    }
    
    • 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
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99

    上述代码的执行结果为:

    Fish Constructor called: Dora
    Fish Constructor called: Tom
    Copy constructor of SmartPointer.
    operator=(const SmartPointer&).
    Fish Destructor called:  Tom
    operator*() of SmartPointer.
    Aloha: Dora
    operator->() of SmartPointer.
    Aloha: Dora
    Refernce count of Dora fish: 3
    Fish Destructor called:  Dora
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    类似于第7章中介绍的模板函数,SmartPointer被设计为一个模板类,其类型参数T需要在使用该类时于<>内提供。

    🚩第22 ~ 26行:SmartPointer对象包含两个私有属性,其中,ptr为指向动态对象的原始指针;refCount则为指向引用计数的指针。如前所述,该引用计数用于记录指向动态对象的存活智能指针对象的个数。

    🚩第27 ~ 35行:下述情况之一,releaseReference()成员函数将被调用,以释放该指针对动态对象的引用。

    • 智能指针对象析构时;
    • 智能指针准备绑定其它对象前。

    🚩第28 ~ 29行:如果智能指针是空指针,直接返回。

    🚩第30行:引用计数递减。

    🚩第31 ~ 34行:如果引用计数归零,说明该指针所指向的动态对象已经不被需要,将其释放,同时释放引用计数。

    🚩第38 ~ 42行:构造函数接受一个动态对象的指针作为参数。函数体内,原始指针得到保存,引用计数被创建并置1。

    🚩第44 ~ 46行:析构函数内调用releaseReference()函数释放指针对动态对象的引用。如果该智能指针是指向该动态对象的最后一个存活的智能指针,该函数会释放动态对象。

    🚩第49 ~ 54行:拷贝构造函数。该函数通过复制来初始化一个新的智能指针对象。函数体完成了下述工作:

    • 从源对象复制原始指针及引用计数指针。
    • 引用计数递增,因为又产生了一个新的指向该动态对象的智能指针。

    🚩第57 ~ 65行:operator=()操作符函数用于对一个已经存在的智能指针对象进行赋值。

    🚩第59 ~ 60行:如果智能指针对象自己赋值给自己,什么也不做,直接返回*this做为表达式的值。请读者注意,a = a这种表达式在语法上是合法的,虽然多数编译器会给出警告信息。

    🚩第61行:在绑定到新的动态对象之前,先释放对原动态对象的引用。

    🚩第62 ~ 64行:绑定至新的动态对象,递增引用计数。

    🚩第65行:返回*this作为表达式的值。

    🚩第69 ~ 74行:间接操作符*的重载函数。当对一个智能指针使用间接操作符时,该函数会被调用,以获得其所指向的动态对象的引用。

    🚩第71 ~ 72行:如果原始指针不为空,返回所指向的动态对象的引用。

    🚩第73行:对一个空指针使用间接操作符是非法的,抛出异常(exception)▲。

    🚩第77 ~ 82行:指向操作符->的重载函数。当对一个智能指针使用指向操作符时,该函数会被调用。该函数预期返回原始指针。

    🚩第79 ~ 80行:如果原始指针非空,返回原始指针。

    🚩第81行:对一个空指针应用指向操作符是非法的,抛出异常。

    🚩第85 ~ 87行:查询智能指针所指向的动态对象的引用计数,该引用计数表明当前指向该动态对象的智能指针的数量。

    接下来,main()函数演示了上述SmartPointer类型的使用方法。

    🚩第91 ~ 92行:创建Dora鱼、Tom鱼及相关智能指针。执行结果的第1 ~ 2行对应两条鱼的构造输出。

    🚩第93行:f3的拷贝构造函数被执行,以f1为实参。执行结果的第3行对应拷贝构造函数的输出。

    🚩第94行:该行代码执行前f2已存在,故f2的operator=()函数被执行,以f1为实参。执行结果的第4行对应operator=()函数的输出。当前,f2是指向Tom鱼的唯一智能指针,f2的被赋值将间接导致Tom鱼被释放,执行结果的第5行对应Tom鱼的析构输出。

    🚩第95行:对智能指针f2应用间接操作符以获取f2所指向的动态对象的引用,本行事实上导致了f2的operator*()函数的执行,该函数出的输出见执行结果的第6行。以返回的Dora鱼对象的引用为基础,sayHello()成员函数被执行,执行结果的第7行可以看到来自Dora鱼的问候。

    🚩第96行:对智能指针f2应用指向操作符,本行事实上导致了f2的operator->()函数的执行,其输出对应执行结果的第8行。以该函数返回的Dora鱼的原始指针为基础,sayHello()成员函数被执行,执行结果的第9行可再次看到来自Dora鱼的问候。

    🚩第97行:目前为止,共有f1、f2和f3共三个智能指针指向Dora鱼,referenceCount()返回Dora鱼的引用计数,其值应为3,见执行结果的第10行。

    到了main()函数的结尾,智能指针f1、f2和f3作为栈对象,相继被析构并释放对Dora鱼的引用。其中,最后一个被析构的智能指针发现Dora鱼的引用计数归零,将其释放。执行结果的第11行,对应Dora鱼的析构输出。

    为了帮助更多的年轻朋友们学好编程,作者在B站上开了两门免费的网课,一门零基础讲Python,一门零基础C和C++一起学,拿走不谢!

    简洁的C及C++
    由编程界擅长教书,教书界特能编程的海洋饼干叔叔打造
    Python编程基础及应用
    由编程界擅长教书,教书界特能编程的海洋饼干叔叔打造

    如果你觉得纸质书看起来更顺手,目前Python有两本,C和C++在出版过程中。

    Python编程基础及应用

    Python编程基础及应用实验教程
    在这里插入图片描述

  • 相关阅读:
    Kubernetes 系统化学习之 基本概念篇
    刷题记录(NC235611 牛牛国的战争,NC23803 DongDong认亲戚,NC235622 叠积木)
    i5 6500 HD530 台式机黑苹果记录
    探索编译软件栈新范式;高端GPU禁售的影响;陈天奇DL系统免费课程|AI系统前沿动态
    世界环境日 | 周大福用心服务推动减碳环保
    K8s安装乐维5.0应用部署文档
    【从0到1设计一个网关】性能优化---缓存
    自定义linux cp命令
    深入URP之Shader篇5: SimpleLit Shader分析(1)
    基于负相关误差函数的4集成BP神经网络matlab建模与仿真
  • 原文地址:https://blog.csdn.net/SeaBiscuitUncle/article/details/126576489