手写 shared_ptr

前言

手写一个 shared_ptr


代码

头文件

#ifndef SHARED_PTR_H
#define SHARED_PTR_H

#include <atomic>
#include <utility>

namespace tyz {
	
	template<typename T>
	class default_deleter {
	public:
		void operator()(T* ptr) {
			delete ptr;
		}	
	}; 

	template<typename T, typename deleter = default_deleter<T>>
	class shared_ptr {
	private:
		std::atomic_int *user_count = nullptr;
		T* ptr = nullptr;
	
	public:
		shared_ptr() = default;
		shared_ptr(T* );
		shared_ptr(const shared_ptr& );
		shared_ptr(shared_ptr&& );
		shared_ptr& operator=(const shared_ptr &);
		shared_ptr& operator=(shared_ptr&& );
		~shared_ptr();
		void swap(shared_ptr& lhs);
		T* get() { return ptr;}
		int count() { return *user_count;}
		void reset();
		T* operator->() { return ptr;}
		T& operator*()  { return *ptr;}
	
	};	

	template<typename T, typename deleter>
	shared_ptr<T, deleter>::shared_ptr(T* ptr_) 
		:user_count(new std::atomic_int(1)), ptr(ptr_){
	}

	template<typename T, typename deleter>
	shared_ptr<T, deleter>::shared_ptr(const shared_ptr& lhs) :
		ptr(lhs.ptr), user_count(lhs.user_count) {
		++*user_count;
	}

	template<typename T, typename deleter>
	shared_ptr<T, deleter>::shared_ptr(shared_ptr&& lhs) {
		std::swap(ptr, lhs.ptr);
		std::swap(user_count, lhs.user_count);
	}

	 
	template<typename T, typename deleter>
	shared_ptr<T, deleter>& shared_ptr<T, deleter>::operator=(const shared_ptr &lhs) {
		shared_ptr temp(lhs);
		swap(temp);
		return *this;
	}


	template<typename T, typename deleter>
	shared_ptr<T, deleter>& shared_ptr<T, deleter>::operator=(shared_ptr&& lhs) {
		if (this != &lhs) {
			if (ptr) {
				if (--*user_count <= 0) {
					deleter()(ptr);
					delete user_count;
				}
				ptr = nullptr;
				user_count = nullptr;
			}
			swap(lhs);
		}
		return *this;
	}

	template<typename T, typename deleter>
	shared_ptr<T, deleter>::~shared_ptr() {
		if (ptr) {
			if (--*user_count <= 0) {
				deleter()(ptr);
				delete user_count;
			}
		}
	}

	template<typename T, typename deleter>
	void shared_ptr<T, deleter>::swap(shared_ptr& lhs) {
		std::swap(ptr, lhs.ptr);
		std::swap(user_count, lhs.user_count);
	}

	template<typename T, typename deleter>
	void shared_ptr<T, deleter>::reset() {
		if (ptr) {
			if (--*user_count <= 0) {
				deleter()(ptr);
				delete user_count;
			}
			ptr = nullptr;
			user_count = nullptr;
		}
	}
	
	// when we use shared_ptr, we cann't designate the deleter
    template<typename T, typename... Args>
    shared_ptr<T> make_shared(Args&&... args) {
        return shared_ptr<T>(new T (std::forward<Args>(args)...));
    } 
}

#endif

测试代码

#include "shared_ptr.h"
#include <iostream>


using std::cout;
using std::endl;

struct Student {
	int id;
	int age;
	Student(int _id, int _age):id(_id), age(_age){}
};

void print(tyz::shared_ptr<Student> &s) {
	if (s.get() == nullptr) {
		cout << "nullptr" << endl;
		return;
	}
	cout << "id: " << s->id << endl 
		 << "age: " << s->age << endl;
	cout << s.count() << endl;
}

int main() {

	//tyz::shared_ptr<Student> test_ptr(new Student(1, 20));

	tyz::shared_ptr<Student> test_ptr = tyz::make_shared<Student>(1, 20);
	tyz::shared_ptr<Student> test_ptr2 = tyz::make_shared<Student>(1, 20);
	
	tyz::shared_ptr<Student> ptr1 = test_ptr;	// copy constructor
	print(ptr1);
	ptr1 = test_ptr2;							// copy assignment
	print(test_ptr1);
	print(test_ptr2);
	tyz::shared_ptr<Student> ptr2(test_ptr);	// copy constructor
	print(ptr2);

	tyz::shared_ptr<Student> ptr3(std::move(test_ptr));	// move constructor
	print(ptr3);
	print(test_ptr);							// should be nullptr 

	tyz::shared_ptr<Student> ptr4 = std::move(ptr1);	// move assignment
	print(ptr4);
	print(ptr1);								// should be nullptr

	ptr4.reset();
	print(ptr2);								// wheather user_count - 1 ?

}

注意事项

  1. 在写赋值操作符时,请始终记得处理自赋值
  2. 用 拷贝并交换 写出的拷贝赋值是天生 异常安全并能处理自赋值的
  3. 写移动函数时,直接置空指针并交换 达到最高效率
  4. 实际的 shared_ptr 的 user_count 应为一个结构体,里面不只含有引用计数,还有弱引用计数,删除器等
  5. 智能指针并非多线程安全的,原因在于 这篇文章
  6. make_shared 中不应加入 deleter 原因:

“如果使用自定义删除器,则在创建智能指针对象时不能使用make_unique或make_shared函数。
这个想法是,如果您需要一种专门的方法来删除对象,那么您可能也需要一种专门的方法来创建它们。” 并且 基于 new 创建 应当基于 delete 销毁,不应该有自定义删除器。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值