shared_ptr和unique_ptr的简单实现

shared_ptr

template <typename T>
class Sptr {
public:
	//默认构造函数
	Sptr()
		:ptr(nullptr),
		counter(new int(0))
	{}
	//构造函数
	Sptr(T* pIn)
		:ptr(pIn),
		counter(new int(1))
	{}
	//析构函数
	~Sptr() {
		if (ptr != nullptr && -- * counter == 0) {
			del();
		}
	}
	//拷贝构造函数
	Sptr(const Sptr& sIn)
		:ptr(sIn.ptr),
		counter(sIn.counter)
	{	
		++*counter;
	}
	//拷贝赋值运算符
	Sptr& operator=(const Sptr& sIn) {
		//记得考虑自我赋值
		if (this != &sIn) {
			if (ptr != nullptr && -- * counter == 0) {
				del();
			}
			ptr = sIn.ptr;
			counter = sIn.counter;
			++* counter;
		}
		return *this;
	}
	//移动构造函数
	Sptr(Sptr &&sIn)
		:ptr(sIn.ptr),
		counter(sIn.counter)
	{
		sIn.ptr = nullptr;
		sIn.counter = nullptr;
	}
	//移动赋值运算符
	Sptr& operator=(Sptr&& sIn) {
		if (this != &sIn) {
			if (ptr != nullptr && -- * counter == 0) {
				del();
			}
			ptr = sIn.ptr;
			counter = sIn.counter;
			sIn.ptr = nullptr;
			sIn.counter = nullptr;
		}
		return *this;
	}
	//reset
	void reset() {
		if (ptr != nullptr && -- * counter == 0) {
			del();
		}
	}
	void reset(T* pIn) {
		if (ptr != nullptr && -- * counter == 0) {
			del();
		}
		ptr = pIn;
		*counter = 1;
	}
	//get
	T* get() {
		return ptr;
	}
	//*
	T& operator*() {
		return *ptr;
	}
	//->
	T* operator->() {
		return ptr;
	}
	//unique
	bool unique() {
		return *counter == 1;
	}
	//use_count
	int use_count() {
		return *counter;
	}
	//swap
	void swap(Sptr &sIn) {
		swap(*this, sIn);
	}
private:
	T* ptr;
	int* counter;
	//析构调用
	void del() {
		delete ptr;
		delete counter;
		ptr = nullptr;
		counter = nullptr;
	}
};

unique_ptr

template <typename T>
class Uptr {
public:
	//构造函数
	Uptr(T* pIn = nullptr)
		:ptr(pIn)
	{}
	//析构函数
	~Uptr() {
		if (nullptr == ptr) return;
		del();
	}
	//拷贝构造函数
	Uptr(const Uptr&) = delete;
	//拷贝赋值运算符
	Uptr& operator=(const Uptr&) = delete;
	//移动构造函数
	Uptr(Uptr&& pIn) 
		:ptr(pIn.release())
	{
	}
	//移动赋值运算符
	Uptr& operator=(Uptr&& uIn) {
		if (this != &uIn) {
			del();
			ptr = uIn.release();
		}
		return *this;
	}

	//reset
	void reset(T* pIn = nullptr) {
		del();
		ptr = pIn;
	}
	//release
	T* release() {
		T* ret = ptr;
		ptr = nullptr;
		return ret;
	}
	//get
	T* get() {
		return ptr;
	}
	//swap
	void swap(Uptr& uIn) {
		swap(*this, uIn);
	}
	//*
	T& operator*() {
		return *ptr;
	}
	//->
	T* operator->() {
		return ptr;
	}
private:
	T* ptr;
	//析构调用
	void del() {
		delete ptr;
		ptr = nullptr;
	}
};

注意

  1. 注意拷贝构造函数和拷贝赋值符的区别,Test t = x用的是拷贝构造函数,t = x用的是拷贝赋值符
  2. 定义了移动构造函数或移动赋值符,vsstudio会删除默认的拷贝构造函数和拷贝赋值符,即不自己重新声明就不能使用这两种拷贝函数
  3. weak_ptr要用shared_ptr初始化,使用前需要检查,换成shared_ptr使用
  4. shared_ptr的引用计数器是线程安全的,但对象不是线程安全的
  5. make_shared和make_unique在动态内存分配一个对象并初始化,返回指向对象的相应智能指针
  • 作用①:不使用的话,需要进行两次堆内存分配(对象一次,智能指针一次);使用的话,只进行一次堆内存分配
  • 作用②:异常安全。假设在函数两个形参都是shared_ptr,实参使用new的形式,执行过程可能是先进行两次new,再利用两个对象对shared_ptr进行初始化。如果new出第一个对象后,第二个new出现异常,那么第一个对象就发生了内存泄漏
  1. shared_ptr的计数器为什么要用指针:比如用的是int类型计数器,一个函数的形参是shared_ptr,在函数里面用了new shared_ptr = 参数shared_ptr做了赋值构造,按道理原shared_ptr的引用计数器需要-1,但是实际上函数调用处的实参shared_ptr不受影响
posted @ 2021-01-16 01:04  肥斯大只仔  阅读(334)  评论(0编辑  收藏  举报