C++RAII Memory Management Technology

insert image description here

1. What is RAII memory management technology?

  • After C++ introduced the exception mechanism,Jumps in code execution flowIt becomes unpredictable, if you use ordinary pointers for memory management, it is difficult to avoidmemory leakThe problem (execution flow jumps cause the heap area resources cannot be released)
  • RAII technology refers toUse the life cycle of objects to manage memory resources, as far as the management of memory resources in the heap area is concerned, it refers to: encapsulating the pointer in the class, inclass object constructionGet heap resources, whenAt the end of the class object's lifetime,passclass object destructorAutomatically complete the release of heap area resources, such class objects aresmart pointer
    • Smart pointers can effectively avoid the problem of memory leaks in development, and at the same time save developers a lot of time and effort

2. Smart pointer

  • Smart pointers in the C++11 standard library are mainly divided into three categories:insert image description here

unique_ptr

  • unique_ptrCopying between objects is not allowed, iean unique_ptrobjectmanageA heap memory resource, is a one-to-one relationship
  • unique_ptrThe simple implementation principle of :
	//不允许拷贝的智能指针
	//delfunc是堆区资源释放函数,用于调用delete或者delete[]
	template<class T,class delfunc>
	class unique_ptr
	{
    
    
	public:
		unique_ptr(T * ptr = nullptr)
			:_ptr(ptr)
		{
    
    }

		~unique_ptr()
		{
    
    
			if (_ptr)
			{
    
    
				delfunc del;
				del(_ptr);
				std::cout << "delete" << std::endl;
			}
		}


		//让智能指针可以像指针一样被使用
		T& operator*()
		{
    
    
			return *_ptr;
		}

		T* operator->()
		{
    
    
			return _ptr;
		}

		//禁止unique_ptr对象间的拷贝
		unique_ptr(const unique_ptr<T, delfunc>& unptr) = delete;
		unique_ptr<T, delfunc>& operator=(const unique_ptr<T, delfunc>& unptr) = delete;
	private:
		T* _ptr;
	};
  • When using pointers to manage heap resources, we will let them point tosingle objectorarray of objects,single objectdeletecompletes resource release witharray of objectsThe design purpose of the class template parameters to be used delete[]to complete resource release is to distinguish the above two situations, allowing users to passunique_ptrdelfuncdesign functorway to choose between deleteanddelete[]

shared_ptr

  • shared_ptrIt is a smart pointer that allows copying, but shared_ptrwhen copying occurs between objects, it will appearmultiple smart pointersSimultaneous managementsame heap memorysituation, shared_ptrthroughreference countThe technology avoids the situation where the same heap resource is released multiple times:insert image description here
  • Implementation ideas for reference counting:
    • shared_ptrEncapsulate a pointer internally to int * recountmaintainreference count variable
    • Whenever an shared_ptrobject performsConstruct and apply for heap resourcesAt the same time, apply for an int variable in the heap area as the shared_ptrheap area resource pointed to by the objectreference count variable
    • Whenever shared_ptrcopied, along with int * recountthe copy, and then letreference count variableJust add one (the implementation of assignment overloading also needs to be consideredreference count variableminus one andHeap resource releaseThe problem)
    • Whenever shared_ptrdestructor,reference count variableminus one, ifreference count variableIf it is reduced to 0, the heap resources will be releasedinsert image description here
  • shared_ptrThe simple implementation principle of :
    //允许拷贝的智能指针,利用引用计数解决内存管理冲突
	//delfunc是堆区资源释放函数,用于调用delete或者delete[]
	template<class T, class delfunc>
	class shared_ptr
	{
    
    
	public:
		//构造智能指针(同时创建引用计数变量)
		shared_ptr(T* ptr = nullptr)
			:_ptr(ptr),
			 _recount(new int(1))
		{
    
    }
		shared_ptr(const shared_ptr<T, delfunc>& shptr)
			: _ptr(shptr._ptr),
			  _recount(shptr._recount)
		{
    
    
			//智能指针拷贝增加引用计数
			(*_recount)++;
		}
		shared_ptr<T, delfunc>& operator=(const shared_ptr<T, delfunc>& shptr)
		{
    
    
			if (_ptr != shptr._ptr)
			{
    
    
				//智能指针指向改变,其先前指向的堆区内存和引用计数变量需要处理
				Release();
				//完成智能指针拷贝并增加引用计数
				_ptr = shptr._ptr;
				_recount = shptr._recount;
				++(*_recount);
			}
			return (*this);
		}
		~shared_ptr()
		{
    
    
			Release();
		}


		//让智能指针可以像指针一样被使用
		T& operator*()
		{
    
    
			return *_ptr;
		}

		T* operator->()
		{
    
    
			return _ptr;
		}
		T* getptr() const
		{
    
    
			return _ptr;
		}
	private:
		//将资源释放函数进行封装,方便复用
		//引用计数减一,若引用计数减为0则释放资源
		void Release()
		{
    
    
			//引用计数减一
			--(*_recount);
			//引用计数为0则释放资源
			if (*_recount == 0)
			{
    
    
				if (_ptr)
				{
    
    
					delfunc del;
					del(_ptr);
					std::cout << "delete" << std::endl;
				}
				//同时注意释放引用计数变量
				delete _recount;
			}
		}
	private:
		T* _ptr;
		int* _recount;
	};
  • shared_ptrInside the class, we also need to solve thereference count variablebroughtthread safetyproblem, not discussed here

circular reference problem

  • shared_ptrused inself referencing structwill appear inThe problem that the object cannot be destructed:

template<class T>
class deletefunc
{
    
    
public:
	void operator()(T* ptr)
	{
    
    
		delete  ptr;
	}
};
// 循环引用
struct ListNode
{
    
    
	int _val;
	shared_ptr<ListNode,deletefunc<ListNode>> _next;
	shared_ptr<ListNode,deletefunc<ListNode>> _prev;
	~ListNode()
	{
    
    
		cout << "~ListNode()" << endl;
	}
};

// 循环引用
void test_shared_cycle()
{
    
    
	share_ptr<ListNode, deletefunc<ListNode>> n1(new ListNode);
	share_ptr<ListNode, deletefunc<ListNode>> n2(new ListNode);
	n1->_next = n2;
	n2->_prev = n1;
}
  • When test_shared_cycle()the function is executed, both linked list nodes areCannot be destructed normally, shared_ptrcausing a circular reference problem:insert image description here
  • n1The destruction of the node depends on the destruction of the pointer n2in the node , the destruction of the pointer in the node depends on the destruction of the node, the destruction of the node depends on the destruction of the pointer in the node , and the destruction of the pointer in the node depends on the node Destruction. This reciprocation constitutes a circular dependency that causes both nodes to fail to be released._prevn2_prevn2n2n1_nextn1_nextn1
  • weak_ptrIt is designed to solve the circular reference problem

weak_ptr

  • weak_ptrsmart pointerDoes not participate in the application and release of heap memory, and will not increase the reference count of a specific memory block (its function is similar to that of a normal pointer), and supportsweak_ptr copy construction and assignment of reference parametersshared_ptr
  • weak_ptrSimple implementation principle:
	//用于配合share_ptr的使用用于循环引用的场景
	//delfunc是堆区资源释放函数,用于调用delete或者delete[]
	//weak_ptr不参与资源的申请和释放
	template<class T, class delfunc>
	class weak_ptr
	{
    
    
	public:
		weak_ptr()
			:_ptr(nullptr)
		{
    
    }

		~weak_ptr()
		{
    
    }
		
		weak_ptr(const weak_ptr<T, delfunc>& wptr)
			:_ptr(wptr._ptr)
		{
    
    }
		weak_ptr(const share_ptr<T, delfunc>& shptr)
			:_ptr(shptr.getptr())
		{
    
    }
		weak_ptr<T, delfunc>& operator=(const weak_ptr<T, delfunc>& wptr)
		{
    
    
			_ptr = wptr._ptr;
			return (*this);
		}
		weak_ptr<T, delfunc>& operator=(const share_ptr<T, delfunc>& shptr)
		{
    
    
			_ptr = shptr.getptr();
			return (*this);
		}

		//让智能指针可以像指针一样被使用
		T& operator*()
		{
    
    
			return *_ptr;
		}

		T* operator->()
		{
    
    
			return _ptr;
		}
	private:
		T* _ptr;
	};
  • existself referencing structweak_ptrThe problem of circular references can be avoided by using
    insert image description here

Guess you like

Origin blog.csdn.net/weixin_73470348/article/details/132286323