本节将实现一个名为SmartPointer的简化版本的shared_ptr模板类,相关C++代码如下。
版权声明
本文可以在互联网上自由转载,但必须:注明出处(作者:海洋饼干叔叔)并包含指向本页面的链接。
本文不可以以纸质出版为目的进行改编、摘抄。
1 | //Project - SmartPointer |
上述代码的执行结果为:
1 | Fish Constructor called: Dora |
类似于第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 ~ 66行: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鱼的析构输出。