重点:
1.引用计数在堆上(原本应为原子变量)
2.引用计数增加减少需要加锁保证线程安全。
3.内部实现Release函数用于释放资源
4.未实现,增加自定义删除器可以将Release修改为模板函数,传入可调用参数。对于shared_ptr,删除器应当作为构造函数参数传入。故而成员函数需要有std::function对象。
#ifndef SHARED_PTR_SHARED_PTR_H
#define SHARED_PTR_SHARED_PTR_H
#include <mutex>
template<typename T>
class Shared_ptr{
public:
Shared_ptr(T * row) :
_row_ptr(row),
_ref_count(new int(1)),
_ref_mux(new std::mutex)
{}
~Shared_ptr(){ release(); }
//拷贝构造
Shared_ptr(const Shared_ptr<T> &sp) :
_row_ptr(sp._row_ptr),
_ref_count(sp._ref_count),
_ref_mux(sp._ref_mux)
{ add_ref(); }
//拷贝赋值
Shared_ptr<T>& operator=(const Shared_ptr<T> &sp){
if (this->_row_ptr != sp._row_ptr){
release(); //释放管理的旧资源
_row_ptr = sp._row_ptr;
_ref_count = sp._ref_count;
_ref_mux = sp._ref_mux;
add_ref();
}
return *this;
}
public:
int& use_count(){ return *_ref_count; }
T& operator*(){ return *_row_ptr; }
T* operator->(){ return _row_ptr; }
T* get(){ return _row_ptr; };
void reset(T *sp){
if (this->_row_ptr != sp){
release(); //释放旧资源,减少引动计数
_row_ptr = sp;
_ref_count = new int(1);
_ref_mux = new std::mutex;
} else
add_ref();
}
private:
T *_row_ptr;
int *_ref_count;
std::mutex *_ref_mux;
//减少引用计数或释放内存
void release(){
std::unique_lock<std::mutex> lock(*_ref_mux);
if (--(*_ref_count) == 0){
delete _row_ptr;
delete _ref_count;
_row_ptr = nullptr; //避免悬空指针
_ref_count = nullptr;
}
}
//保证线程安全的前提下加锁增加引用计数
void add_ref(){
std::unique_lock<std::mutex> lock(*_ref_mux);
++(*_ref_count);
}
};
#endif //SHARED_PTR_SHARED_PTR_H
测试程序:
#include <iostream>
#include <string>
#include "Shared_ptr.h"
int main() {
Shared_ptr<std::string> ptr1(new std::string("hello"));
Shared_ptr<std::string> ptr2(ptr1);
std::cout << "ptr2 use_count = " << ptr2.use_count() << "ptr1 use_count = " << ptr1.use_count() << std::endl;
Shared_ptr<std::string> ptr3 = ptr2;
std::cout << "ptr3 use_count = " << ptr3.use_count() << std::endl;
std::cout << *ptr2 << std::endl;
auto str = new std::string("ni hao");
ptr2.reset(str);
std::cout << *ptr2 <<" ptr2 usecount = " << ptr2.use_count() << std::endl;
std::cout << ptr1.use_count() << std::endl;
return 0;
}