智能指针shared_ptr类的简单实现

环境:

vs2019 clang编译器


my_shared_ptr.h:

ps:不用另外写默认构造函数,shared_ptr(T* p = nullptr)构造函数就包含shared_ptr()了

#pragma once

#include <atomic>   //实现引用计数的读写的线程安全性
#include <algorithm>//std::swap

using namespace std;

namespace my_ptr {

	template <typename T>
	class shared_ptr {
	private:
		T* _ptr;
		atomic<size_t*> cnt;

	public:
		shared_ptr(T* p = nullptr) :_ptr(p)
		{
			if (p == nullptr) cnt = new size_t(0);
			else cnt = new size_t(1);  cout << "shared_ptr(T* p = nullptr)\n";
		}

		//复制构造
		shared_ptr(const shared_ptr& sp) :_ptr(sp._ptr) {
			if (sp._ptr == nullptr) *cnt = 0;
			else {
				auto countp = sp.cnt.load(); 
				(*countp)++;
				cnt = countp; //调用cnt.store(countp);
			}
			cout << "copy_construct_from\n";
		}

		//移动构造
		shared_ptr(const shared_ptr&& sp) :_ptr(sp._ptr), cnt(sp.cnt) {
			sp._ptr = nullptr;
			sp.cnt = nullptr;
			cout << "move_construct_from\n";
		};

		//析构
		~shared_ptr()
		{
			cout << "~shared_ptr() \n";
			if (-- * cnt == 0) {
				delete _ptr; 
				_ptr = nullptr;
				delete cnt;
				cnt = nullptr;
				cout << "delete cnt\n";
			}
		}

		//读取引用计数
		int use_count() const noexcept {
			return static_cast<int>(*cnt);
		}

		//是否独占
		bool is_unique() noexcept {
			return *cnt == 1;
		}
		//获取原始指针
		T* get() const noexcept {
			return _ptr;
		}

		//释放所有权
		void reset() noexcept {
			shared_ptr().swap(*this);
		}
		//释放并获得sp的原始指针所有权
		void reset(const shared_ptr& sp) {
			shared_ptr(sp).swap(*this);
		}

		//交换对象所有权
		void swap(shared_ptr&& sp) noexcept {
			T* tmp = _ptr;
			_ptr = sp._ptr;
			sp._ptr = tmp;

			auto countp = cnt.load();
			cnt = sp.cnt.load();
			sp.cnt = countp;
		}
		void swap(shared_ptr& sp) noexcept {
			this->swap(move(sp));
		}

		//重载赋值运算符=左值
		shared_ptr& operator=(const shared_ptr& sp) noexcept {
			shared_ptr(sp).swap(*this);
			return *this;
		}
		//重载赋值运算符=右值
		shared_ptr& operator=(const shared_ptr&& sp) noexcept {
			shared_ptr(move(sp)).swap(*this);
			return *this;
		}

		//重载*,返回原始指针所指对象/值
		T& operator*() const noexcept {
			return *get();
		}

		//重载->,直接返回原始指针
		T* operator->() const noexcept {
			return get();
		}

		//重载==,直接比较原始指针是否相同
		bool operator==(const shared_ptr& right) const noexcept {
			return this->get() == right.get();
		}
		//重载!=
		bool operator!=(const shared_ptr& right) const noexcept {
			return this->get() != right.get();
		}
		//重载<
		bool operator<(const shared_ptr& right) const noexcept {
			return this->get() < right.get();
		}
		//重载>
		bool operator>(const shared_ptr& right) const noexcept {
			return this->get() > right.get();
		}
	};
}

测试程序:


#include <iostream>

#include "my_shared_ptr.h"

using namespace std;

int main() {

	int* p0 = new int(1);
	my_ptr::shared_ptr<int> sp(p0);

	int* p = sp.get();
	cout << "sp.is_unique() " << sp.is_unique() << endl;
	cout << "sp.use_count() " << sp.use_count() << endl;
	cout << endl;

	my_ptr::shared_ptr<int> sp1(sp);
	cout << "sp.use_count() " << sp.use_count() << endl;
	cout << "sp1.use_count() " << sp1.use_count() << endl;
	cout << endl;

	cout << "sp1.reset()" <<  endl;
	sp1.reset();
	cout << "sp.use_count() " << sp.use_count() << endl;
	cout << "sp1.use_count() " << sp1.use_count() << endl;
	cout << endl;

	cout << "sp1.reset(sp)" <<  endl;
	sp1.reset(sp);
	cout << "sp.use_count() " << sp.use_count() << endl;
	cout << "sp1.use_count() " << sp1.use_count() << endl;
	cout << endl;


	my_ptr::shared_ptr<int> sp2(new int(1));
	cout << "sp2.use_count() " << sp2.use_count() << endl;
	cout << endl;

	my_ptr::shared_ptr<int> sp3;
	cout << "sp3.use_count() " << sp3.use_count() << endl;
	cout << endl;
}

测试结果:

shared_ptr(T* p = nullptr)
sp.is_unique() 1
sp.use_count() 1

copy_construct_from
sp.use_count() 2
sp1.use_count() 2

sp1.reset()
shared_ptr(T* p = nullptr)
~shared_ptr()
sp.use_count() 1
sp1.use_count() 0

sp1.reset(sp)
copy_construct_from
~shared_ptr()
sp.use_count() 2
sp1.use_count() 2

shared_ptr(T* p = nullptr)
sp2.use_count() 1

shared_ptr(T* p = nullptr)
sp3.use_count() 0

~shared_ptr()
~shared_ptr()
delete cnt
~shared_ptr()
~shared_ptr()
delete cnt

注意:如果使用命名空间包含类,则命名空间的定义要放在使用之前的位置。

namespace Test{
...
class A;
}

//使用方式包括
//1.使用整个命名空间
using Test;

//2.使用命名空间部分内容
using Test::A;

//3.不用using直接使用,前面要加 命名空间::
Test::A objA;

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值