C++ implements smart pointers (3)

1. Implementation version v3

  • Reference counting techniques:
Each object is responsible for maintaining a count of all references to the object. The reference counter is incremented when a new reference points to the object, and decremented when a reference is removed. When the reference count reaches zero, the object will release the occupied resources.

The reference count needs to be stored in the referenced resource object. A resource object corresponds to a reference count. When the reference count is 0, the resource object can be destroyed.

Need to modify the following functions to implement the counting function:

  1. Constructors that receive different object types: This constructor implementation is relatively simple, just add 1 to the reference count
  2. Destructor: In the implementation of the destructor, the delete operation cannot be performed directly, but the reference count needs to be decremented by 1. When the reference count is 0, the delete operation can be performed.
  3. Copy constructor: The implementation of the copy constructor, the underlying pointer is shared, and then the reference count is incremented by 1.
  4. Assignment operator: The implementation of the assignment operation is a little more complicated. It involves adding 1 to the reference count of the newly pointed object, decrementing the reference count of the original pointed object by 1, and destroying the original pointed object if necessary. It is worth noting here that the implementation of our new assignment operation no longer needs the if (this == &other) return *this; statement to deal with the situation of self-assignment. Readers can analyze the implementation of our new assignment operation by themselves. There is no need to handle self-assignment through an if statement.
  • Reference counting base class
In order to use reference counting technology, our smart pointers can no longer be used as native pointers and can point to arbitrary resource objects. Our smart pointers can only point to resource classes that implement the incRefCount and decRefCount methods.

Generally, according to the object-oriented design method, we will abstract the relevant content of reference count management into a base class, so that any resource class that is expected to be referenced by smart pointers only needs to inherit this class.

  • Header file smartpointer.h
/*
* file name : smartpointer.h
* desp : smart pointer version v3
*/
#ifndef __SMARTPOINTER_H__
#define __SMARTPOINTER_H__

template <typename T> // Define the smart pointer class as a template class
class SmartPointer {
public:
    // default constructor
    SmartPointer():mPointer(NULL) {std::cout <<"Create null smart pointer."<< std::endl;}    
    // Constructors that accept different object types
    SmartPointer(T *p):mPointer(p) {
        std::cout <<"Create smart pointer at "<<static_cast<const void*>(p)<<std::endl;
        /* The smart pointer points to class T, and the reference count is incremented by 1*/
        if (mPointer) mPointer->incRefCount();
    }     
    // destructor
    ~SmartPointer(){
        std::cout << "Release smart pointer at "<<static_cast<const void*>(mPointer)<<std::endl;
        // Implement the automatic destruction mechanism of memory resources
        if (mPointer && mPointer->decRefCount()==0) delete mPointer;
    }
    // copy constructor
    SmartPointer(const SmartPointer &other):mPointer(other.mPointer) {
        std::cout <<"Copy smart pointer at "<<static_cast<const void*>(other.mPointer)<<std::endl;
       // increment the reference count by 1
       if(mPointer) mPointer->incRefCount();
    }     
   // assignment operator         
   SmartPointer &operator = (const SmartPointer &other) {
       T *temp(other.mPointer);
       // The new pointer to the object, the reference count value is incremented by 1
       if (temp) temp->incRefCount();
       // The original point to the object, the reference count value is decremented by 1, if the reference count is 0 after decrementing 1, the original resource object is destroyed
       if (mPointer && mPointer->decRefCount()==0) delete mPointer;
       // smart pointer points to the new resource object
       mPointer = temp;  
       return *this;
   }

private:
    T *mPointer; // Point to the actual memory resource corresponding to the smart pointer, define the internal resource pointer type according to the automatic parameter deduction rules
};

/*Reference count base class*/
class RefBase   
{   
    public:   
        RefBase() : mCount(0){ }   
        void incRefCount(){   
            mCount++;   
        }   
        int decRefCount(){   
            return --mCount;
        }   
        // Debug interface, return the current reference count of the object   
        int getRefCount () {   
            return mCount;   
        }     
        virtual ~RefBase(){ }
    private:   
        int mCount;   
};   
#endif // __SMARTPOINTER_H__
  • Test file sptestcase3.cpp
/*
* file name : sptestcase3.cpp
* desp : smart pointer test code case3 test the reference counting function of smart pointer
*/

#include <iostream>
#include "smartpointer.h"

/* SomeClass class inherited from reference counting base class */
class SomeClass: public RefBase{
public:
    SomeClass(){std::cout << "SomeClass default constructor !"<<std::endl;}
    ~SomeClass(){std::cout << "SomeClass deconstructor !"<<std::endl;}
};

void testcase3(void)
{
    SomeClass *pSomeClass =  new SomeClass(); //1
    SmartPointer<SomeClass> spOuter = pSomeClass;
    std::cout << "SomeClass Ref Count (" << pSomeClass->getRefCount() << ") outer 1."<< std::endl;
    { // inner block
          SmartPointer<SomeClass> spInner = spOuter;
          std::cout << "SomeClass Ref Count (" << pSomeClass->getRefCount() << ") inner."<< std::endl;
    }
    std::cout << "SomeClass Ref Count (" << pSomeClass->getRefCount() << ") outer 2."<< std::endl;
    // delete pSomeClass ; no delete operation is required and cannot be performed!

    std::cout << "new another SomeClass class for spOuter."<< std::endl;
    SmartPointer<SomeClass> spOuter2 = new SomeClass();
    spOuter = spOuter2;// SomeClass from new at 1 will be automatically released  
}

int main(void)
{
    testcase3();
    return 0;
}

Result analysis


  • The v3 version basically implements the function of smart pointers, and the next step can improve the functions as pointers: dereference, null, comparison operations

2. Knowledge point checking and filling vacancies

  • wild pointer
Suppose we have multiple smart pointers pointing to a memory resource, when one of the pointers is destroyed, it will automatically release the memory resource it points to, which will eventually lead to the fact that others are still in use and reference the memory resource. is a smart pointer, smartpointer2 is a wild pointer. Therefore, reference counting technology is used.


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325680275&siteId=291194637