Simple analysis of C + + intelligent pointer

Posted by shmeeg on Sun, 02 Jan 2022 15:38:44 +0100

The meaning of smart pointer

In C + +, new and delete are the keywords to apply for and destroy heap memory. After applying for heap memory, programmers often forget to delete to release heap memory, which is easy to cause a phenomenon - memory leakage, that is, a piece of heap memory is not released after being applied, so that other programs cannot use this heap memory, resulting in a waste of heap memory, It reduces the development efficiency of C + +. In java and other languages, there is only the new keyword, but not the delete keyword. This is because of the memory recycling mechanism of java language. Due to the previous extreme pursuit of code running efficiency by C + +, this mechanism has not been introduced. But. With the release of C11 standard, smart pointer is gradually accepted by everyone. Although it will reduce the efficiency, it also greatly reduces the memory leakage and other problems encountered by developers in the development process.

The smart pointer is not a pointer, but a kind of template. The object instantiated through the smart pointer can automatically release the memory when the object is destroyed, instead of being released manually by the developer.

Realization of intelligent pointer

For the generation and destruction of an object, there are the following steps:
Object generation:

  • Open up heap memory;
  • Call the constructor.

Destruction of objects:

  • Call the destructor;
  • Free memory;

According to the important characteristics of object destruction: automatically call the destructor. We only need to write the delete memory release function to the destructor. When the object is destroyed, the system can automatically release heap memory, so as to avoid memory leakage and other problems.

Intelligent pointer under C++11 standard

C + + provides developers with two types of smart pointers:

  • Smart pointer with reference count
  • Smart pointer without reference count

They are auto_ptr,unique_ptr,shared_ptr,weak_ptr and other smart pointers. Where auto_ptr is a smart pointer introduced in c98 standard, and the remaining smart pointers were later introduced into C + + with reference to the implementation of smart pointers in boost library. They all exist in the memory library, so when using smart pointers

auto_ptr

auto_ptr existed in the STL library as early as the release of c98 standard, but now it has been abandoned due to various performance problems. Study auto first_ Source code of PTR:

template<class _Ty>
	class auto_ptr
		{	// wrap an object pointer to ensure destruction
public:
	typedef auto_ptr<_Ty> _Myt;
	typedef _Ty element_type;

	// Constructor
	explicit auto_ptr(_Ty *_Ptr = 0) _THROW0()
		: _Myptr(_Ptr)
		{	// construct from object pointer
		}
	
	// Copy the constructor and call the release method
	auto_ptr(_Myt& _Right) _THROW0()
		: _Myptr(_Right.release())
		{	// construct by assuming pointer from _Right auto_ptr
		}
	
	// Assignment operator function, call release method
	template<class _Other>
		_Myt& operator=(auto_ptr<_Other>& _Right) _THROW0()
		{	// assign compatible _Right (assume pointer)
		reset(_Right.release());
		return (*this);
		}
	// Destructor
	~auto_ptr() _NOEXCEPT
		{	// destroy the object
		delete _Myptr;
		}
		
	// Pointer dereference operator overload
	_Ty& operator*() const _THROW0()
		{	// return designated value
 #if _ITERATOR_DEBUG_LEVEL == 2
		if (_Myptr == 0)
			_DEBUG_ERROR("auto_ptr not dereferencable");
 #endif /* _ITERATOR_DEBUG_LEVEL == 2 */

		return (*get());
		}
	
	// Pointer overload
	_Ty *operator->() const _THROW0()
		{	// return pointer to class object
 #if _ITERATOR_DEBUG_LEVEL == 2
		if (_Myptr == 0)
			_DEBUG_ERROR("auto_ptr not dereferencable");
 #endif /* _ITERATOR_DEBUG_LEVEL == 2 */

		return (get());
		}
	
	// Get method -- get pointer address
	_Ty *get() const _THROW0()
		{	// return wrapped pointer
		return (_Myptr);
		}
	
	// Deprive original auto_ptr's ownership of the pointer gives the current auto_ptr ownership of pointer
	_Ty *release() _THROW0()
		{	// return wrapped pointer and give up ownership
		_Ty *_Tmp = _Myptr;
		_Myptr = 0;
		return (_Tmp);
		}

	// Destroys the specified object and stores the new pointer
	void reset(_Ty *_Ptr = 0)
		{	// destroy designated object and store new pointer
		if (_Ptr != _Myptr)
			delete _Myptr;
		_Myptr = _Ptr;
		}

private:
	_Ty *_Myptr;	// the wrapped object pointer
	};

Shared_ptr

shared_ The biggest difference between PTR and other smart pointers is that reference counting is added, that is, the use object of a resource can be counted. If the use object of this resource becomes 0, this block of memory needs to be deleted. But usually with weak_ptr use.
The code is as follows:

ount;
};
trmplate<class T>
class Shard_ptr{
	public:
		Shared_ptr(T* p=0):_ptr(p)
		{
			cnt=new Counter;
			if(p)
			{
				cnt->shardCount=1; 
			}
		}
		~Shared_ptr()
		{
			release();
		}
		Shared_ptr(Shared_ptr<T> const &src)  //copy construction  
		{
			_ptr=src._ptr;
			//Of the original shared object 
			(src.cnt)->shardCount++;
		}
		Shared_ptr(WeakPtr<T>&const w)
		{
			//Copy weakptr object pointer 
			_ptr=w._ptr;
			(w.cnt)->sharedCount++;
			cnt=w.cnt;
			
		}
		Shared_ptr<T>& operator=(Shared_ptr<T>& src)
		{
			//Prevent self reference 
			if(this!=&src)
			{
				//Release ownership of source managed objects 
				release(); 
				(src.cnt)->sharedCount++;
				cnt=src.cnt;
				_ptr=src._ptr; 
			}
			return *this;
		 } 
		T& operator*()
		{
			return* _ptr;
		}
		T* operator->()
		{
			return _ptr;
		}
		friend class WeakPtr<T>;
	protected:
		//Release the ownership of the source object. If the count is 0, the memory will be reclaimed 
		void release()
		{
			cnt->shardCount--;
			
			if(cnt->shardCount<1)
			{
				delete _ptr;
				if(cnt->weakCount<1)
				{
					delete cnt;
					cnt=NULL;
				}
			}
		}
	private:
		T* _ptr;
		Counter* cnt;
};

weak_ptr

weak_ For shareptr_ PTR, whose copy constructor is shared_ PTR and weak_ptr object is constructed without overloading * and - >, and lock() is used to get an available object. weak_ptr() does not have the right to use memory, so it cannot use resources directly. lock() is usually used to generate a shared_ PTR.

template<class T>
class WeakPtr
{
	public:
		WeakPtr()
		{
			_ptr=0;
			cnt=new Counter();
		}
		WeakPtr(Sharedptr<T>& src):_ptr(src._ptr),_cnt(src.cnt)
		{
			cnt.weakCount++;
		} 
		WeakPtr(WeakPtr<T>& src):_ptr(src._ptr),cnt(src.cnt)
		{
			cnt.weakCount++;
		 } 
		 ~WeakPtr()
		 {
		 	release(); 
		 }
		 WeakPtr<T>& operator=(WeakPtr<T>& src)
		 {
		 	if(this!=*src)
		 	{
		 		//Release the original management object 
		 		release();
		 		cnt=src.cnt;
		 		cnt->weakCount++;
		 		_ptr=src._ptr;
			 }
			 return *this;
		 }
		 WeakPtr<T>& operator=(WeakPtr<T>& src)
		 {
		 	if(this!=*src)
		 	{
		 		release();
		 		cnt=src.cnt;
		 		cnt->shardCount++;
		 		_ptr=src._ptr; 
			 }
			 return *this;
		 }
		 Sharedptr<T> lock()
		 {
		 	//Convert weakptr to sharedptr 
		 	return Sharedptr<T>(*this);
		 }
		 bool expired()
		 {
		 	if(cnt)
		 	{
		 		if(cnt->shardCount>0)
		 		{
		 			return false;
				 }
			 }
			 return true;
		  } 
		  friend class Sharedptr<T>;
	protected:
		void release()
		{
			if(cnt)
			{
				cnt->weakCount--;
				if(cnt->weakCount<1 && cnt->s<1)
				{
					cnt=NULL;
				}
			}
		}
		
	private:
		T* _ptr;
		Counter* cnt;	
};

Introduce weak_ptr is to solve the problem of strong intelligent pointer Shared_ptr may cause cross reference, so that the counter will never decrease to 0, so that the resource cannot be released. Therefore, strong smart pointers are used to define objects, and weak smart pointers are used to define objects.

Topics: C++ pointer memory management