C + + daily question: category and principle implementation of intelligent pointer

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

   
  1. // The reference counter class is used to store the number of pointers to the same object
  2. template< typename T>
  3. class Counter
  4. {
  5. private:
  6. // Data member
  7. T *ptr; // Object pointer
  8. int cnt; // Reference counter
  9. // Friend class declaration
  10. template< typename T>
  11. friend class SmartPtr;
  12. // Member function
  13. // Constructor
  14. Counter(T *p) // p is the pointer to the dynamically allocated object
  15. {
  16. ptr = p;
  17. cnt = 1;
  18. }
  19. // Destructor
  20. ~ Counter()
  21. {
  22. delete ptr;
  23. }
  24. };

(2) Pointer class

   
  1. // Smart pointer class
  2. template< typename T>
  3. class SmartPtr
  4. {
  5. private:
  6. // Data member
  7. Counter<T> *ptr_cnt; //
  8. public:
  9. // Member function
  10. // Normal constructor initializes the count class
  11. SmartPtr(T *p)
  12. {
  13. ptr_cnt = new Counter<T>(p);
  14. }
  15. // copy constructor
  16. SmartPtr( const SmartPtr &other)
  17. {
  18. ptr_cnt = other.ptr_cnt;
  19. ptr_cnt->cnt++;
  20. }
  21. // Assignment operator overloaded function
  22. SmartPtr & operator=( const SmartPtr &rhs)
  23. {
  24. ptr_cnt = rhs->ptr_cnt;
  25. rhs.ptr_cnt->cnt++;
  26. ptr_cnt->cnt--;
  27. if (ptr_cnt->cnt == 0)
  28. delete ptr_cnt;
  29. return * this;
  30. }
  31. // Dereference operator overloaded function
  32. T & operator*()
  33. {
  34. return *(ptr_cnt->cnt);
  35. }
  36. // Destructor
  37. ~ SmartPtr()
  38. {
  39. ptr_cnt->cnt--;
  40. if (ptr_cnt->cnt == 0)
  41. delete ptr_cnt;
  42. else
  43. cout << "also" << ptr_cnt->cnt << "Pointers to the underlying object" << endl;
  44. }
  45. };

(3) Use and test

   
  1. #include<iostream>
  2. using namespace std;
  3. // Test function
  4. void test()
  5. {
  6. int *p = new int( 42);
  7. {
  8. SmartPtr<int> sptr1(p); // Out of scope, the counter is decremented by 1
  9. {
  10. SmartPtr<int> sptr2(sptr1); // Out of scope, the counter is decremented by 1
  11. {
  12. SmartPtr<int> sptr3(sptr1); // Out of scope, the counter is decremented by 1
  13. }
  14. }
  15. }
  16. cout << *p << endl; // The dynamically allocated object has been released, so the garbage value is output
  17. }
  18. // Main function
  19. int main()
  20. {
  21. test();
  22. return 0;
  23. }

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.

Added by alex.saidani on Fri, 29 Oct 2021 03:24:22 +0300