共享指针原理:
shared_ptr主要是用来自动管理动态创建对象的销毁,记录对象被引用的次数,当引用计数清零的时候,把指向的内存区域自动释放掉
如果要手动实现一个共享指针的话就需要一个共享指针类,类中存着被指向的对象的指针
当对象被多个共享指针指向的时候,就需要一个共享的引用计数器counter
当对象被共享指针指向的时候,引用计数器为2
当一个共享指针被释放后,引用计数器的值减1
当都断的时候,引用计数器变为0,这时候清理对象A
共享指针计数器:
class Counter
{
public:
Counter()
{
count = 1;
}
void add()
{
count++;
}
void sub()
{
count--;
}
int get() const
{
return count;
}
private:
int count;
};
共享指针类:
template <typename T>
class Sp
{
public:
Sp(); //默认构造函数
~Sp(); //析构函数
Sp(T *ptr); //参数构造函数
Sp(const Sp &obj); //复制构造函数
Sp &operator=(const Sp &obj); //重载=
T *get(); //得到共享指针指向的类
int getcount(); //得到引用计数器
private:
T *my_ptr; //共享指针所指向的对象
Counter* counter; //引用计数器
void clear(); //清理函数
};
//默认构造函数,参数为空,构造一个引用计数器
template<typename T>
Sp<T>::Sp()
{
my_ptr = nullptr;
counter = new Counter();
}
//复制构造函数,新的共享指针指向旧的共享指针所指对象
template<typename T>
Sp<T>::Sp(const Sp &obj)
{
//将所指对象也变为目标所指的对象
my_ptr = obj.my_ptr;
//获取引用计数器,使得两个共享指针用一个引用计数器
counter = obj.counter;
//使这个对象的引用计数器+1
counter->add();
};
//重载=
template<typename T>
Sp<T> &Sp<T>::operator=(const Sp&obj)
{
//清理当前所引用对象和引用计数器
clear();
//指向新的对象,并获取目标对象的引用计数器
my_ptr = obj.my_ptr;
counter = obj.counter;
//引用计数器+1
counter->add();
//返回自己
return *this;
}
//创建一个共享指针指向目标类,构造一个新的引用计数器
template<typename T>
Sp<T>::Sp(T *ptr)
{
my_ptr = ptr;
counter = new Counter();
}
//析构函数,出作用域的时候,调用清理函数
template<typename T>
Sp<T>:: ~Sp()
{
clear();
}
//清理函数,调用时将引用计数器的值减1,若减为0,清理指向的对象内存区域
template<typename T>
void Sp<T>::clear()
{
//引用计数器-1
counter->sub();
//如果引用计数器变为0,清理对象
if(0 == counter->get())
{
if(my_ptr)
{
delete my_ptr;
}
delete counter;
}
}
//当前共享指针指向的对象,被几个共享指针所引用
template<typename T>
int Sp<T>::getcount()
{
return counter->get();
};
class A{
public:
A()
{
cout<<"A construct!"<<endl;
};
~A()
{
cout<<"A destruct!"<<endl;
};
};
构造测试对象A:
class A{
public:
A()
{
cout<<"A construct!"<<endl;
};
~A()
{
cout<<"A destruct!"<<endl;
};
};
测试函数:
int main()
{
cout<<"start"<<endl;
{
//创建共享指针sp指向新创建的对象A
Sp<A> sp(new A);
cout<<sp.getcount()<<endl;
{
//创建共享指针sp2指向A,这时有两个共享指针指向A
Sp<A> sp2 = sp;
cout<<sp.getcount()<<endl;
}
cout<<sp.getcount()<<endl;
}
//出了作用域后,引用计数器-1,此时对象被析构,内存被回收
cout<<"over"<<endl;
}
输出结果:
这时候,如果多个线程都在使用这个引用计数器的时候,容易引发多线程安全问题,所以在这里添加互斥锁
为计数器类添加线程安全保障
class Counter
{
public:
Counter()
{
my_Mutex = new mutex;
count = 1;
}
void add()
{
my_Mutex->lock();
count++;
my_Mutex->unlock();
}
void sub()
{
my_Mutex->lock();
count--;
my_Mutex->unlock();
}
int get() const
{
return count;
}
private:
mutex* my_Mutex;
int count;
};
使用原子变量实现多线程安全保障
count使用原子变量来实现线程安全
class Counter
{
public:
Counter()
{
count = 1;
}
void add()
{
count++;
}
void sub()
{
count--;
}
int get() const
{
return count;
}
private:
std::atomic<int> count;
};
全部代码:
#include<iostream>
#include<atomic>
using namespace std;
class Counter
{
public:
Counter()
{
count = 1;
}
void add()
{
count++;
}
void sub()
{
count--;
}
int get() const
{
return count;
}
private:
std::atomic<int> count;
};
template <typename T>
class Sp
{
public:
Sp(); //默认构造函数
Sp(T *ptr); //参数构造函数
Sp(const Sp &obj); //复制构造函数
~Sp(); //析构函数
Sp &operator=(const Sp &obj); //重载=
T *get(); //得到共享指针指向的类
int getcount(); //得到引用计数器
private:
T *my_ptr; //共享指针所指向的对象
Counter* counter; //引用计数器
void clear(); //清理函数
};
//默认构造函数,参数为空,构造一个引用计数器
template<typename T>
Sp<T>::Sp()
{
my_ptr = nullptr;
counter = new Counter();
counter->add();
}
//复制构造函数,新的共享指针指向旧的共享指针所指对象
template<typename T>
Sp<T>::Sp(const Sp &obj)
{
//将所指对象也变为目标所指的对象
my_ptr = obj.my_ptr;
//获取引用计数器,使得两个共享指针用一个引用计数器
counter = obj.counter;
//使这个对象的引用计数器+1
counter->add();
};
//重载=
template<typename T>
Sp<T> &Sp<T>::operator=(const Sp&obj)
{
//清理当前所引用对象和引用计数器
clear();
//指向新的对象,并获取目标对象的引用计数器
my_ptr = obj.my_ptr;
counter = obj.counter;
//引用计数器+1
counter->add();
//返回自己
return *this;
}
//创建一个共享指针指向目标类,构造一个新的引用计数器
template<typename T>
Sp<T>::Sp(T *ptr)
{
my_ptr = ptr;
counter = new Counter();
}
//析构函数,出作用域的时候,调用清理函数
template<typename T>
Sp<T>:: ~Sp()
{
clear();
}
//清理函数,调用时将引用计数器的值减1,若减为0,清理指向的对象内存区域
template<typename T>
void Sp<T>::clear()
{
//引用计数器-1
counter->sub();
//如果引用计数器变为0,清理对象
if(0 == counter->get())
{
if(my_ptr)
{
delete my_ptr;
}
delete counter;
}
}
//当前共享指针指向的对象,被几个共享指针所引用
template<typename T>
int Sp<T>::getcount()
{
return counter->get();
};
class A{
public:
A()
{
cout<<"A construct!"<<endl;
};
~A()
{
cout<<"A destruct!"<<endl;
};
};
int main()
{
cout<<"start"<<endl;
{
//创建共享指针sp指向新创建的对象A
Sp<A> sp(new A);
cout<<sp.getcount()<<endl;
{
//创建共享指针sp2指向A,这时有两个共享指针指向A
Sp<A> sp2 = sp;
cout<<sp.getcount()<<endl;
}
cout<<sp.getcount()<<endl;
}
//出了作用域后,引用计数器-1,此时对象被析构
cout<<"over"<<endl;
}