C++ 智能指针 shared_ptr、unique_ptr、weak_ptr

什么是智能指针

这三种智能指针都定义在memory头文件中。

C++的智能指针其实就是对普通指针的封装(即封装成一个类),通过重载 * 和 ->两个运算符,使得智能指针表现的就像普通指针一样。

智能指针实现原理

智能指针(smart pointer)的通用实现技术是使用引用计数(reference count)。智能指针类将一个计数器与类指向的对象相关联,引用计数跟踪该类有多少个对象的指针指向同一对象。每次创建类的新对象时,初始化指针就将引用计数置为1;当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数;对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数;调用析构函数时,析构函数减少引用计数(如果引用计数减至0,则删除基础对象)。
 

  • shared_ptr

利用引用计数->每有一个指针指向相同的一片内存时,引用计数+1,每当一个指针取消指向一片内存时,引用计数-1,减为0时释放内存。

在典型的实现中,shared_ptr 只保有两个指针:

  1. get()所返回的指针;(基础对象的内存地址)
  2. 指向控制块的指针。(控制块对象的内存地址)

控制块是一个动态分配的对象,其中包含:

  1. 指向被管理对象的指针或被管理对象本身;(基础对象的内存地址)
  2. 删除器;(Deleter,类型擦除)
  3. 分配器;(Allocator,类型擦除)
  4. 占用被管理对象的shared_ptr的数量(strong refs强引用的引用计数);
  5. 涉及被管理对象的weak_ptr的数量(weak refs弱引用的引用计数) 。

  • week_ptr

            弱指针 ->辅助shared_ptr解决循环引用的问题

            weak_ptr是为了配合shared_ptr而引入的一种智能指针,因为它不具有普通指针的行为,没有重载operator*和->,它的最大作用在于协助shared_ptr工作,像旁观者那样观测资源的使用情况。weak_ptr可以从一个shared_ptr或者另一个weak_ptr对象构造,获得资源的观测权。但weak_ptr没有共享资源,它的构造不会引起指针引用计数的增加。使用weak_ptr的成员函数use_count()可以观测资源的引用计数,另一个成员函数expired()的功能等价于use_count()==0,但更快,表示被观测的资源 (也就是shared_ptr的管理的资源)已经不复存在。weak_ptr可以使用一个非常重要的成员函数lock()从被观测的shared_ptr 获得一个可用的shared_ptr对象, 从而操作资源。但当expired()==true的时候,lock()函数将返回一个存储空指针的shared_ptr。
 

  • unique_ptr

           “唯一”拥有其所指对象,同一时刻只能有一个unique_ptr指向给定对象(禁止拷贝、赋值),可以释放所有权,转移所有权。

unique_ptr实现对基础对象资源的独占,实现原理是将unique_ptr类的“拷贝构造函数”、“拷贝赋值运算符”均声明为delete,因此无法实施拷贝和赋值操作,但是可以“移动构造”和“移动赋值”。 转移一个unique_ptr将会把所有权也从源指针转移给目标指针(源指针被置为空)。

unique_ptr必须直接初始化,且不能通过隐式转换来构造,因为unique_ptr的构造函数被声明为explicit。

unique_ptr 的常用操作:

u.get();        //返回unique_ptr中保存的裸指针
u.reset();        //重置unique_ptr
u.release();    //放弃指针的控制权,返回裸指针,并将unique_ptr自身置为空。
u.swap();        //交换两个unique_ptr所指向的对象



#include <atomic>
using namespace std;
// shared_ptr()


namespace shp {

	// 定义一个 callable对象类作为默认删除器
	template<typename T>
	class deafult_deleter {
	public:
		void operator()(T* ptr) {
			delete ptr;
		}

	};


	template<typename T, typename deleter = deafult_deleter<T>>
	class shared_ptr {
	private:
		// 原生指针
		T ptr = nullptr;
		// 指向 count的指针,事实上 count本是更复杂的结构体其中一个成员,所以用指针保留扩展性
		std::atomic<int>* count = nullptr;	// 每个 std::atomic 模板的实例化和全特化定义一个原子类型

	public:
		// 默认构造函数
		shared_ptr() = default;	// 在非模板中,仅当您希望该类支持该操作(然后测试它是否支持)时才使用 =default ,关键字 =default 优化了这种行为,用该关键字标记重写的默认拷贝构造函数,编译器会隐式生成一个版本
		// 原生指针构造
		shared_ptr(T* _ptr);
		// 拷贝构造函数
		shared_ptr(const shared_ptr& lsh);
		// 移动构造函数
		shared_ptr(shared_ptr&& lsh);
		// 拷贝赋值运算符
		shared_ptr& operator=(const shared_ptr& lsh);
		// 移动赋值运算符
		shared_ptr& operator= (shared_ptr&& lsh);
		// 析构接口
		~shared_ptr();


		// 箭头函数运算符重载
		T* operator->();
		// 解引用运算符重载
		T& operator*();

		
		// 智能指针交换接口
		void swap(shared_ptr& lsh);
		// 解除对当前指针的管理,如果有新的 ptr则托管新的指针
		void reset(T* _ptr = nullptr);
		// 获取引用计数
		int count();
		// 获取原生指针
		T* get();




	};




	// 原生指针构造
	template<typename T, typename deleter>
	shared_ptr<T, deleter>::shared_ptr(T* _ptr):ptr(_ptr), count(new atomic<int>(1)){}

	// 拷贝构造函数
	template<typename T,typename deleter>
	shared_ptr<T, deleter>::shared_ptr(const shared_ptr& lsh) {
		ptr = lsh.ptr;
		count = lsh.count;
		++* count;
	}


	// 移动构造函数
	template<typename T, typename deleter>
	shared_ptr<T, deleter>::shared_ptr(shared_ptr&& lsh) {
		swap(ptr, lsh.ptr);
		swap(count, lsh.count)
	}

	

	// 拷贝赋值运算符,使用 copy&swap的方式实现自赋值
	template<typename T,typename deleter>
	shared_ptr<T, deleter>& shared_ptr<T, deleter>::operator=(const shared_ptr& lsh) {
		shared_ptr<T, deleter> lsh_copy(lsh);
		swap(lsh_copy);
		return *this;
	}


	// 移动赋值运算符
	template<typename T, typename deleter>
	shared_ptr<T, deleter>& shared_ptr<T, deleter>::operator*(shared_ptr&& lsh) {
		if (this != &lsh) {	// 避免自我赋值
		// 如果原本有托管对象
			if (ptr) {
				--* count;
				if (*count <= 0) {
					deleter()(ptr);
					deleter count;
				}
				ptr = nullptr;
				count = nullptr;
			}

			swap(lsh);
		}
		return *this;

	}


	// 析构接口
	template<typename T, typename deleter>
	shared_ptr<T, deleter>::~shared_ptr() {
		if (ptr) {
			--* count;
			if (*count <= 0) {
				deleter()(ptr);
				deleter count;
			}
		}
	}


	// 箭头运算符重载
	template<typename T, typename deleter>
	T* shared_ptr<T, deleter>::operator->() {
		return ptr;
	}

	// 解引用运算符重载
	template<typename T, typename deleter>
	T& shared_ptr<T, deleter>::operator*() {
		return *ptr;
	}

	// swap交换
	template<typename T, typename deleter>
	void shared_ptr<T, deleter>::swap(shared_ptr& lsh) {
		swap(ptr, lsh.ptr);
		swap(count, lsh.count);
	}

	// 解除当前指针的管理,如果有新的 ptr则托管新的指针
	template<typename T, typename deleter>
	void shared_ptr<T, deleter>::reset(T* _ptr) {
		if (ptr) {	// 如果当前 shared_ptr 有托管对象,先释放原托管
			--*count;
			if (*count <= 0) {
				deleter()(ptr);
				deleter count;
			}
			ptr = nullptr;
			count = nullptr;
		}
		// 是否有新托管
		if (_ptr) {
			ptr = _ptr;
			count = mew atomic<int>(1);
		}
	}


	// 获取引用计数
	template<typename T, typename deleter>
	int shared_ptr<T, deleter>::count() {
		return *count;
	}


	// 获取原生指针
	template<typename T, typename deleter>
	T* shared_ptr<T, deleter>::get() {
		return ptr;
	}




	template <typename T>
	class unique_ptr {
	private:
		T* ptr = nullptr;

	public:
		// 普通构造
		unique_ptr(T* p = nullptr) : ptr(p) {
		}

		// 析构
		~unique_ptr() {
			if (nullptr != this->ptr) {
				delete this->ptr;
				this->ptr = nullptr;
			}
		}

		// 移动构造
		unique_ptr(unique_ptr&& obj) : unique_ptr() {
			*this = ::std::move(obj);
		}

		// 移动赋值
		unique_ptr& operator=(unique_ptr&& rhs) {
			if (this == &rhs) {
				return *this;
			}
			// 夺取右值的资源
			this->~unique_ptr();
			this->ptr = rhs.ptr;
			rhs.ptr = nullptr;
			return *this;
		}

	public:  // 修改器
		// 返回一个指向被管理对象的指针,并释放所有权
		T* release() {
			T* res = this->ptr;
			this->ptr = nullptr;
			return res;
		}

		// 替换被管理对象
		void reset(T* p = nullptr) {
			// 直接调用operator=
			*this = unique_ptr<T>(p);
		}

		// 交换被管理对象
		void swap(unique_ptr& other) {
			::std::swap(this->ptr, other.ptr);
		}

	public:  // 观察器
		// 返回指向被管理对象的指针
		T* get() {
			return this->ptr;
		}

		// 返回用于析构被管理对象的删除器
		// 本简单样例不考虑删除器
		// D& get_deleter();

		// 检查是否有关联的被管理对象
		operator bool() {
			return nullptr != get();
		}

		// operator*
		T& operator*() {
			assert(get());
			return *this->ptr;
		}

		// operator->
		T* operator->() {
			assert(get());
			return this->ptr;
		}
	};




	template<class T>
	class weak_ptr {
	public:
		using element_type = remove_extent_t<T>;


		// 构造函数接口
		constexpr weak_ptr() noexcept {	// 静态编译关键字 constexpr 表示它所声明的变量或者函数,都在静态编译时就已经完成
			ptr = 0;
			count = 0;

		}

		template(class Y)weak_ptr(const shared_ptr<Y>& w) noexcept :ptr(s.ptr), count(s.count) {	// noexcept 表示无需抛出异常 noexcept(false) 表示抛出异常	throw(...)表示接收任何类型异常
			count->w++;		
		}

		weak_ptr(const weak_ptr& w) noexcept;

		template<class Y> weak_ptr(const weak_ptr<Y>& w) noexcept :ptr(w.ptr), count(w.count) {
			count->w++;
		}

		weak_ptr(weak_ptr&& w) noexcept;

		template<class Y>weak_ptr(weak_ptr<Y>&& w) noexcept;

		// 析构函数接口
		~weak_ptr() {
			release();
		}

		// 赋值构造函数
		weak_ptr& operator=(const weak_ptr& w) noexcept;

		template<class Y> weak_ptr& operator=(const weak_ptr<Y>& w) noexcept {
			if (this != &w) {
				release();
				count = w.count;
				count->w++;
				ptr = w.ptr;
			}
			return *this;
		}

		template<class Y>weak_ptr& operator=(const shared_ptr<Y>& w) noexcept {
			release();
			count = w.count;
			count->w++;
			ptr = w.ptr;
			return *this;
			
		}

		weak_ptr& operator=(weak_ptr&& w) noexcept;

		template<class Y> weak_ptr& operato = (weak_ptr<Y> && w) noexcept;


		// 接口 swap互换同类型的 weak_ptr 指针
		void swap(weak_ptr& w) noexcept;

		// 将当前 weak_ptr指针置为空指正
		void reset() noexcept;
		
		// 查看指向和当前 weak_ptr指针相同的 shared_ptr指针的数量
		long count() const noexcept;

		// 判断当前 weak_ptr指针是否过期(指针为空,或者指向的堆内存已经被释放)
		bool expired() const noexcept {
			if (count) {
				if (count->s > 0) {
					return false;
				}
			}
			return true;
		}

		// 如果当前 weak_ptr已经过期,则该函数会返回一格空的 shared_ptr指针,反之该函数返回一格和当前 weak_ptr指向相同 shared_ptr指针
		shared_ptr<T> lock() const noexcept {
			return shared_ptr<T> (*this);
		}

		template<class U>
		bool owner_before(const shared_ptr<U>& b) const noexcept;

		template<class U>
		bool owner_before(const weak_ptr<U>& b) const noexcept;


		friend class shatred_ptr<T>;


	private:
		void release() {
			if (count) {
				count->w--;
				if (count->w < 1 && count->s < 1) {
					count = nullptr;
				}
			}
		}

		T* ptr;
		cpimter* count;



	};

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值