一、Shared_ptr 定义
-
从c++11开始,std给我们提供4中智能指针auto_ptr、unique_ptr、shared_ptr 和 weak_ptr,其中最常用的为unique_ptr、shared_ptr,今天我们看下如何用代码实现shared_ptr的基本功能。
-
首先share_ptr也是一个类。可以实现多个指针指向同一对象(引用计数),有以下3个特性。
- 每使用一次,内部引用计数加1;
- 每析构一次,内部引用计数减1,;
- 引用计数减为0时,自动释放原生指针所指向的内存。
二、代码实现
重点一、我们知道,std提供的shared_ptr的核心就是引用计数,实现方法可以用指针的方式也可以用全局变量的方式,这里我们用指针的方式。多个shared_ptr对象共用同一个指针(指向引用计数)。
int* count; //一个指向引用计数器的指针
重点二、 为什么成员运算符(->)的重载返回类型是原生指针的类型?shared_ptr名为指针,其实是类。对一个类采用成员运算符重载,返回值很自然的就是类中的成员了。
所以我们需要运算符重载:-> * &等这几个运算符
//运算符重载:-> 实现指针功能
T* operator->(){
return ptr;
}
//运算符重载:* 实现取值功能
T& operator*(){
return *ptr;
}
完整代码:
#include<iostream>
using namespace std;
template<typename T>
class MySharedPtr{
public:
//构造函数1,空指针,计数为0
MySharedPtr():count(nullptr),ptr(nullptr){}
//构造函数2,从原生指针构造
MySharedPtr(T* p):count(new int(1)),ptr(p){}
//构造函数3,拷贝构造函数,引用计数器+1,让该对象的指针指向形参对象的指针
MySharedPtr(const MySharedPtr<T>& another){
ptr = another.ptr;
++(*another.count);
count = another.count;
}
//析构函数,使用引用次数减一,判断引用是否为0,为0的话调用delete
~MySharedPtr() {
(*count)--;
if (ptr && *count == 0)
{
delete ptr;
delete count;
cout << "delete ptr ~" << this << endl;
}
}
//运算符重载:-> 实现指针功能
T* operator->(){
return ptr;
}
//运算符重载:* 实现取值功能
T& operator*(){
return *ptr;
}
//运算符重载:& 实现赋值功能
MySharedPtr<T>& operator=(MySharedPtr<T>& another){
if(this == &another) //解决自赋值问题,如果判断是自赋值,直接返回
return *this;
++(*another.count); //another被指向的对象计数加一
if(this->ptr&&--(*this->count)==0){ //如果原来的shared_ptr已经有对象,则让其引用计数减少一,并判断引用是否为0,如果为0,则调用delete释放ptr
delete this->count;
delete this->ptr;
cout << "delete ptr " << this << endl;
}
this->ptr = another.ptr;
this->count = another.count;
return *this;
}
int getCount(){ //计算被引用次数
return *count;
}
private:
T* ptr; //一个指向对象的模板指针
int* count; //一个指向引用计数器的指针
};
简单测试代码:
int main(){
//构造函数2
MySharedPtr<string> pstr(new string("abc")); //new一个对象
cout<<"pstr "<<pstr.getCount()<<" "<<*pstr<<endl;
cout<<endl;
//构造函数3,拷贝构造
MySharedPtr<string> pstr2(pstr);
cout<<"pstr: "<<pstr.getCount()<<" "<<*pstr<<endl;
cout<<"pstr2: "<<pstr2.getCount()<<" "<<*pstr2<<endl;
cout<<endl;
return 0;
}
运行如下: