Smart pointer
1 function of smart pointer
Smart pointer is a class used to store pointers to dynamically allocated objects. It is responsible for automatically releasing dynamically allocated objects and preventing heap memory leakage. Dynamically allocated resources are managed by a class object. When the class object declaration cycle ends, the destructor is automatically called to release resources
2 types of smart pointers
shared_ptr,unique_ptr,weak_ptr,auto_ptr
(1) shared_ptr
Implementation principle: the reference counter method is adopted to allow multiple smart pointers to point to the same object. Whenever one more pointer points to the object, the reference count inside all smart pointers pointing to the object will be increased by 1. Whenever one smart pointer points to the object is reduced, the reference count will be reduced by 1. When the count is 0, the dynamically allocated resources will be automatically released.
1) The smart pointer associates a counter with the object pointed to by the class, and the reference counter tracks how many class objects share the same pointer;
2) Each time a new object of the class is created, the pointer is initialized and the reference count is set to 1;
3) When an object is created as a copy of another object, the copy constructor copies the pointer and increases the corresponding reference count;
4) When assigning an object, the assignment operator reduces the reference count of the object referred to in the left operand (if the reference count is reduced to 0, the object will be deleted) and increases the reference count of the object referred to in the right operand;
5) When the destructor is called, the constructor decreases the reference count (if the reference count decreases to 0, the underlying object is deleted).
(2) unique_ptr
unique_ptr adopts exclusive ownership semantics, a non empty unique_ptr always has the resource it points to. Transfer a unique_ptr will transfer all ownership from the source pointer to the target pointer, and the source pointer will be set to null; So unique_ptr does not support ordinary copy and assignment operations and cannot be used in STL standard containers; Except for the return value of local variables (because the compiler knows that the object to be returned will be destroyed); If you copy a unique_ptr, after the copy, the two unique_ptr will all point to the same resource, causing the same memory pointer to be released multiple times at the end, resulting in program crash.
(3) weak_ptr
weak_ptr: weak reference. One problem with reference counting is that mutual references form a ring (ring reference), so that the memory pointed to by the two pointers cannot be released. Weak is required_ PTR breaks circular references. weak_ptr is a weak reference, which is used to cooperate with shared_ptr is a smart pointer introduced by PTR, which points to a shared_ptr manages the object without affecting the life cycle of the object, that is, it only references and does not count. If a piece of memory is shared_ptr and weak_ptr is referenced simultaneously when all shared_ After PTR deconstruction, whether there is weak or not_ PTR refers to the memory, and the memory will be released. So weak_ptr does not guarantee that the memory it points to must be valid. Use the function lock() to check weak before using it_ Whether PTR is a null pointer.
(4) auto_ptr
auto_ptr does not support copy and assignment operations and cannot be used in STL standard containers. Elements in stl containers often support copy and assignment operations. In this process, auto_ptr passes ownership, auto_ptr adopts exclusive ownership semantics, a non empty unique_ptr always has the resource it points to. Transfer an auto_ptr will transfer all ownership from the source pointer to the target pointer, and the source pointer will be set to null.
Smart pointer code implementation: Two classes are used to realize the function of smart pointer, one is the reference counting class, and the other is the pointer class.
(1) Reference count class
// The reference counter class is used to store the number of pointers to the same object template< typename T> class Counter { private: // Data member T *ptr; // Object pointer int cnt; // Reference counter // Friend class declaration template< typename T> friend class SmartPtr; // Member function // Constructor Counter(T *p) // p is the pointer to the dynamically allocated object { ptr = p; cnt = 1; } // Destructor ~ Counter() { delete ptr; } };
(2) Pointer class
// Smart pointer class template< typename T> class SmartPtr { private: // Data member Counter<T> *ptr_cnt; // public: // Member function // Normal constructor initializes the count class SmartPtr(T *p) { ptr_cnt = new Counter<T>(p); } // copy constructor SmartPtr( const SmartPtr &other) { ptr_cnt = other.ptr_cnt; ptr_cnt->cnt++; } // Assignment operator overloaded function SmartPtr & operator=( const SmartPtr &rhs) { ptr_cnt = rhs->ptr_cnt; rhs.ptr_cnt->cnt++; ptr_cnt->cnt--; if (ptr_cnt->cnt == 0) delete ptr_cnt; return * this; } // Dereference operator overloaded function T & operator*() { return *(ptr_cnt->cnt); } // Destructor ~ SmartPtr() { ptr_cnt->cnt--; if (ptr_cnt->cnt == 0) delete ptr_cnt; else cout << "also" << ptr_cnt->cnt << "Pointers to the underlying object" << endl; } };
(3) Use and test
#include<iostream> using namespace std; // Test function void test() { int *p = new int( 42); { SmartPtr<int> sptr1(p); // Out of scope, the counter is decremented by 1 { SmartPtr<int> sptr2(sptr1); // Out of scope, the counter is decremented by 1 { SmartPtr<int> sptr3(sptr1); // Out of scope, the counter is decremented by 1 } } } cout << *p << endl; // The dynamically allocated object has been released, so the garbage value is output } // Main function int main() { test(); return 0; }
The operation results are as follows:
As shown in the figure, after leaving the braces, the pointer count of the shared base object changes from 3 - > 2 - > 1 - > 0. When the last count is 0, the dynamic allocation object pointed to by pointer p is delete d. At this time, the original value cannot be obtained by using * p, so a garbage value is generated.