C++ STL memory.h 系列一

本文详细介绍了C++ STL中智能指针的概念,包括`auto_ptr`、`unique_ptr`、`shared_ptr`和`weak_ptr`。重点讨论了它们的特点和使用场景,如`auto_ptr`的替代方案,`unique_ptr`的类型转换限制,`shared_ptr`的引用计数和原子操作,以及`weak_ptr`的弱引用管理。文章提供了相关代码链接和实现细节。
摘要由CSDN通过智能技术生成

智能指针 “memory.h”

几个常见的智能指针:

1. auto_ptr

参考链接:https://github.com/Alinshans/MyTinySTL/blob/master/MyTinySTL/memory.h

可以使用unique_ptr替换auto_ptr的功能

其中,并没有类似于unique_ptr、shared_ptr、weak_ptr的判断初始化和赋值时类型不同带来的问题

//------------------------------------------------------------------
	// 模板类: auto_ptr
	// 一个具有严格对象所有权的小型智能指针
    // 用unique_ptr替代

	template<typename T>
	class auto_ptr {
	public:
		using element_type = T;
		
	private:
		T* ptr; // raw pointer

	public:
		explicit auto_ptr(T* p = nullptr) : ptr(p) {}
		auto_ptr(auto_ptr& rhs) :ptr(rhs.release()) {}

		template<typename U>
		auto_ptr(auto_ptr<U>& rhs) : ptr(rhs.release()) {}

		auto_ptr& operator=(auto_ptr& rhs) {
			if (this != &rhs) {
				delete ptr;
				ptr = rhs.release();
			}
			return *this;
		}

		template<typename U>
		auto_ptr& operator=(auto_ptr<U>& rhs) {
			if (this->get() != rhs.get()) {
				delete ptr;
				ptr = rhs.release();
			}
			return *this;
		}

		~auto_ptr() { delete ptr; }

	public:

		T& operator*() { return *ptr; }
		T* operator->() { return ptr; }

		// 获得指针
		T* get() const {
			return ptr;
		}

		// 释放指针
		T* release() {
			T* tmp = ptr;
			ptr = nullptr;
			return tmp;
		}

		// 重置指针
		void reset(T* p = nullptr) {
			if (ptr != p) {
				delete ptr;
				ptr = p;
			}
		}
	};

2. unique_ptr

指针实现都参照https://github.com/RRRadicalEdward/smart_pointers/blob/master/

主要代码在重载运算符,以及数组类型的特例

pointers_are_convertible用于判断FROM和TO类型指针是否可以转化

template<typename FROM, typename TO>
	using pointers_are_convertible = std::enable_if_t<std::is_convertible<FROM*, TO*>::value>;

在实现智能指针之前,先实现默认的删除器。需要留意的是存在有类型为数组的智能指针,因此需要实现删除器的特例:

// default deleter

	template<typename T>
	struct default_deleter final {
	public:
		constexpr default_deleter() noexcept = default;

		template<typename U, typename = pointers_are_convertible<U, T>>
		default_deleter(const default_deleter<U>&) noexcept {}

		void operator()(T* ptr) const noexcept {
			delete ptr;
		}
	};

	template<typename T>
	struct default_deleter<T[]> {
	public:
		constexpr default_deleter() noexcept = default;

		template<typename U, typename = pointers_are_convertible<U, T>>
		default_deleter(const default_deleter<U>&) noexcept {}

		template<typename U, typename = pointers_are_convertible<U, T>>
		default_deleter(default_deleter<U>&&) noexcept {}

		virtual void operator()(T* ptr) const noexcept {
			delete[] ptr;
		}
	};

 以下是class unique_ptr

template<typename T, typename Deleter = default_deleter<T>>
	class unique_ptr final {
	public:
		// Member types
		using pointer      = T*;
		using element_type = T;
		using deleter_type = Deleter;
	private:
		pointer ptr;
		Deleter deleter;

	public:
		// Member function
		constexpr unique_ptr() noexcept : ptr(nullptr) {}
		
		constexpr unique_ptr(std::nullptr_t) noexcept : ptr(nullptr) {}
		
		explicit unique_ptr(pointer res) : ptr(res) {}
		
		unique_ptr(pointer res, const deleter_type& deleter) noexcept
			: ptr(res), deleter(deleter) {}
		
		unique_ptr(pointer res, deleter_type&& deleter)
			: ptr(res), deleter(move(deleter)) {}
		
		unique_ptr(const unique_ptr&) = delete;
		
		unique_ptr(unique_ptr&& other) noexcept
			: ptr(other.release()), deleter(move(other.get_deleter())) {}
		
		template<typename Y, typename D,
			typename = pointers_are_convertible<typename unique_ptr<Y, D>::element_type, T>>
			unique_ptr(unique_ptr<Y, D>&& other) noexcept
			: ptr(static_cast<pointer>(other.release())), 
			deleter(move(static_cast<deleter_type>(other.release()))) {}

		~unique_ptr() {
			if (ptr) {
				deleter(ptr);
			}
		}

	public:
		// operator override
		unique_ptr& operator=(const unique_ptr&) = delete;
		
		unique_ptr& operator=(unique_ptr&& rhs) noexcept {
			if (this == &rhs)
				return *this;
			reset(rhs.release());
			deleter = move(rhs.get_deleter());
			return *this;
		}

		template<typename Y, typename D,
			typename = pointers_are_convertible<typename unique_ptr<Y, D>::element_type, T>>
			unique_ptr & operator=(unique_ptr<Y, D>&& rhs) noexcept {
			reset(static_cast<pointer>(rhs.release()));
			deleter = move(static_cast<Deleter>(rhs.get_deleter()));
			return *this;
		}

	public:
		// modifiers
		pointer release() noexcept {
			pointer old = ptr;
			ptr = nullptr;
			return old;
		}

		void reset(pointer p = pointer{}) noexcept {
			pointer old = ptr;
			ptr = p;
			if (old)
				deleter(old);
		}

		void swap(unique_ptr& other) noexcept {
			if (this != other) {
				swap(ptr, other.ptr);
				swap(deleter, other.deleter);
			}
		}

	public:
		// Observers
		pointer get() const noexcept {
			return ptr;
		}

		deleter_type& get_deleter() noexcept {
			return deleter;
		}

		const deleter_type& get_deleter() const noexcept {
			return deleter;
		}

		explicit operator bool() const noexcept {
			return ptr;
		}

		T& operator*() const {
			return *ptr;
		}

		pointer operator->() const noexcept {
			return ptr;
		}
	};

	template<typename CharT, typename Traits, typename T, typename D>
	std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os,
		const unique_ptr<T, D>& unique) {
		std::cout << *unique;
		return os;
	}

	template<typename T, typename ...Args, 
		typename = enable_if_t<!::std::is_array<T>::value>>
		unique_ptr<T> make_unique(Args&& ...args) {
		return unique_ptr<T>(new T(forward<Args>(args)...));
	}

	template<typename T,
		typename = enable_if_t<is_unbounded_array<T>::value>>
		unique_ptr<T> make_unique(std::size_t size)	{
		return unique_ptr<T>(new std::remove_extent_t<T>[size]());
	}

	/// ???
	template<typename T, typename...Args>
	enable_if_t<is_bounded_array<T>::value>
		make_unique(Args&&...) = delete;

	template<class T,
		typename = enable_if_t<!::std::is_array<T>::value>>
		unique_ptr<T> make_unique_for_overwrite() {
		return unique_ptr<T>(new T);
	}

	template<typename T,
		typename = enable_if_t<is_unbounded_array<T>::value>>
		unique_ptr<T> make_unique_for_overwrite(size_t size) {
		return unique_ptr<T>(new std::remove_extent_t<T>[size]);
	}

	/// ???
	template<typename T, typename...Args>
	enable_if_t<is_bounded_array<T>::value>
		make_unique_for_overwrite(Args&&...) = delete;

	template<typename T1, class D1, typename T2, class D2>
	bool operator==(const unique_ptr<T1, D1>& lhs, const unique_ptr<T2, D2>& rhs) noexcept
	{
		return lhs.get() == rhs.get();
	}

	template<typename T1, class D1, typename T2, class D2>
	bool operator!=(const unique_ptr<T1, D1>& lhs, const unique_ptr<T2, D2>& rhs) noexcept
	{
		return !(lhs == rhs);
	}

	template<typename T1, class D1, typename T2, class D2>
	bool operator<(const unique_ptr<T1, D1>& lhs, const unique_ptr<T2, D2>& rhs) noexcept
	{
		return  lhs.get() < rhs.get();
	}

	template<typename T1, class D1, typename T2, class D2>
	bool operator>(const unique_ptr<T1, D1>& lhs, const unique_ptr<T2, D2>& rhs) noexcept
	{
		return rhs < lhs;
	}

	template<typename T1, class D1, typename T2, class D2>
	bool operator<=(const unique_ptr<T1, D1>& lhs, const unique_ptr<T2, D2>& rhs) noexcept
	{
		return !(rhs < lhs);
	}

	template<typename T1, class D1, typename T2, class D2>
	bool operator>=(const unique_ptr<T1, D1>& lhs, const unique_ptr<T2, D2>& rhs) noexcept
	{
		return !(lhs < rhs);
	}

	template<typename T, class D>
	bool operator==(const unique_ptr<T, D>& lhs, ::std::nullptr_t) noexcept
	{
		return !lhs;
	}

	template<typename T, class D>
	bool operator==(::std::nullptr_t, const unique_ptr<T, D>& rhs) noexcept
	{
		return !rhs;
	}

	template<typename T, class D>
	bool operator!=(const unique_ptr<T, D>& lhs, ::std::nullptr_t) noexcept
	{
		return (bool)lhs;
	}

	template<typename T, class D>
	bool operator!=(::std::nullptr_t, const unique_ptr<T, D>& rhs) noexcept
	{
		return (bool)rhs;
	}

	template<typename T, class D>
	bool operator<(const unique_ptr<T, D>& lhs, ::std::nullptr_t) noexcept
	{
		return lhs.get() < nullptr;
	}

	template<typename T, class D>
	bool operator<(::std::nullptr_t, const unique_ptr<T, D>& rhs) noexcept
	{
		return nullptr < rhs.get();
	}

	template<typename T, class D>
	bool operator>(const unique_ptr<T, D>& lhs, ::std::nullptr_t) noexcept
	{
		return nullptr < lhs;
	}

	template<typename T, class D>
	bool operator>(::std::nullptr_t, const unique_ptr<T, D>& rhs) noexcept
	{
		return rhs < nullptr;
	}

	template<typename T, class D>
	bool operator<=(const unique_ptr<T, D>& lhs, ::std::nullptr_t) noexcept
	{
		return !(nullptr < lhs);
	}

	template<typename T, class D>
	bool operator<=(::std::nullptr_t, const unique_ptr<T, D>& rhs) noexcept
	{
		return !(rhs < nullptr);
	}

	template<typename T, class  D>
	bool operator>=(const unique_ptr<T, D>& lhs, ::std::nullptr_t) noexcept
	{
		return !(lhs < nullptr);
	}

	template<typename T, class D>
	bool operator>=(::std::nullptr_t, const unique_ptr<T, D>& rhs) noexcept
	{
		return !(nullptr < rhs);
	}

	template<typename T, class D>
	void swap(unique_ptr<T, D>& lhs, unique_ptr<T, D>& rhs) noexcept
	{
		lhs.swap(rhs);
	}

	template<typename R, typename D, typename OtherType>
	using is_constructible_from = std::enable_if<
		std::is_same<OtherType*, typename  unique_ptr<R, D>::pointer>::value ||
		std::is_same<OtherType*, std::nullptr_t>::value ||
		(std::is_same<typename unique_ptr<R, D>::pointer, typename unique_ptr<R, D>::element_type*>::value
			&& std::is_convertible<OtherType(*)[], R(*)[]>::value)
	>;

	template<typename R1, class D1, typename R2, class D2>
	using  is_constructible_from_array = std::enable_if<
		std::is_array<R2>::value&&
		std::is_same<typename unique_ptr<R1, D1>::pointer, typename unique_ptr<R1, D1>::element_type*>::value&&
		std::is_same<typename unique_ptr<R2, D2>::pointer, typename unique_ptr<R2, D2>::element_type*>::value&&
		std::is_convertible<typename unique_ptr<R2, D2>::element_type(*)[], typename unique_ptr<R2, D2>::element_type(*)[]>::value
	>;

	template<typename T, typename Deleter>
	class unique_ptr<T[], Deleter> {
	public:
		using pointer = T*;
		using element_type = T;
		using deleter_type = Deleter;

	private:
		pointer ptr;
		deleter_type deleter;

	public:

		constexpr unique_ptr() noexcept
			: ptr(nullptr), deleter(default_deleter<T[]>{}) {}

		constexpr unique_ptr(::std::nullptr_t) noexcept
			: ptr(nullptr), deleter(default_deleter<T[]>{}) {}

		template<typename Y, typename = is_constructible_from<T, deleter_type, Y>>
		explicit unique_ptr(Y* ptr) noexcept
			: ptr(static_cast<pointer>(ptr)), deleter(default_deleter<T[]>{}) {}

		template<typename Y, typename = is_constructible_from<T, deleter_type, Y>>
		unique_ptr(Y* ptr, const deleter_type& deleter) noexcept
			: ptr(static_cast<pointer>(ptr)), deleter(move(deleter)) {}

		unique_ptr(unique_ptr&& other) noexcept
			: ptr(other.release()), deleter(move(other.get_deleter())) {}

		template<typename Y, typename D,
			typename = is_constructible_from_array<T, Deleter, Y, D>>
		unique_ptr(unique_ptr<Y, D>&& other) noexcept
			: ptr(other.release()), deleter(move(other.get_deleter())) {}

		~unique_ptr() {
			if (this->ptr)
				this->deleter(ptr);
		}

	public:
		template<typename Y,
			typename = TypeCanBeConstructedFrom<T, Deleter, Y>>
			void reset(Y* ptr) noexcept
		{
			pointer old_ptr = this->ptr;
			this->ptr = static_cast<pointer>(ptr);

			if (old_ptr)
				deleter(old_ptr);
		}

		void reset(::std::nullptr_t = nullptr) noexcept
		{
			pointer old_ptr = this->ptr;
			this->ptr = nullptr;

			if (old_ptr)
				deleter(old_ptr);
		}


		pointer release() noexcept
		{
			pointer old_ptr = this->ptr;
			this->ptr = nullptr;
			return old_ptr;
		}

		template<typename Y, class D>
		void swap(unique_ptr& other) noexcept
		{
			if (this == &other)
				return;

			tinySTL::swap(this->ptr, other.ptr);
			tinySTL::swap(this->ptr, other.ptr);
		}

		pointer get() const noexcept
		{
			return ptr;
		}


		deleter_type& get_deleter() noexcept
		{
			return deleter;
		}

		const deleter_type& get_deleter() const noexcept
		{
			return deleter;
		}

		explicit operator bool() const noexcept
		{
			return ptr;
		}

		element_type& operator[](size_t index) const
		{
			return get()[index];
		}

		unique_ptr& operator=(unique_ptr&& other) noexcept {
			if (this == &other)
				return *this;

			this->reset(other.release());
			this->deleter = move(other.get_deleter());
			return *this;
		}
	};

3. shared_ptr

链接同上

定义一个ControlBlock类,用于记录指针、拥有shared_ptr和weak_ptr的个数。同时,注意这里采用的是std::atomic_size_t,即std::atomic<std::size_t>实现原子操作,其底层实现参考:https://www.cnblogs.com/cnblogs-wangzhipeng/p/12549179.html

	// 智能指针:shared_ptr
	// 
	//

	// for enable_shared_from_this https://segmentfault.com/a/1190000020861953
	template<typename...>
	using void_t = void;

	template<typename T, typename = void>
	struct can_enable_shared : std::false_type {};

	template<typename T>
	struct can_enable_shared<T, void_t<typename T::class_type>> : std::is_convertible<std::remove_cv_t<T>*,
		typename T::class_type*> {};

	template<typename T, typename Y>
	void check_if_enable_shared(const shared_ptr<T>& other, Y* ptr, std::false_type) {}

	template<typename T, typename Y>
	void check_if_enable_shared(const shared_ptr<T>& other, Y* ptr, std::true_type) {
		if (ptr) {
			ptr->construct_weak_from(other, ptr);
		}
	}

	template<typename T, typename Y>
	void set_enable_shared(const shared_ptr<T>& other, Y* ptr) {
		check_if_enable_shared<T, Y>(other, ptr,
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值