C++ implements smart pointers (2)

1. Implementation version v2

  • copy constructor
  • assignment operator function
For pointers, copying and assignment means sharing the memory resource it refers to, and the implementation corresponding to the smart pointer is that the mPointer member points to the same memory resource.

By default, the C++ compiler will generate the implementation of the copy constructor and assignment operator for the class we define, but for our smart pointers, using the default generated assignment operator will be problematic. as follows:

{ // statement block
  SmartPointer<SomeClass> spclass1 = new SomeClass; //1
  SmartPointer<SomeClass> spclass2 = new SomeClass; //2
  spclass2 = spclass1; //3 call assignment operator
}

Then when the statement block is executed, our expectation is that the new objects in code 1 and 2 should be automatically released by smart pointers, but if we use the implementation of the assignment operator generated by the system by default, 2 new The outgoing object will never be freed, and the new outgoing object will be freed twice.

Implement the smart pointer header file smartpointer.h

/*
* file name : smartpointer.h
* desp : smart pointer version v2
*/
#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;}    
    // Constructor that accepts different pointer types
    SmartPointer(T *p):mPointer(p) {std::cout <<"Create smart pointer at "<<static_cast<const void*>(p)<<std::endl;}     
    // 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) 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;
    }     
   // assignment operator                
   SmartPointer &operator = (const SmartPointer &other) {
        // handle the case of self-assignment
        if (this == &other) return *this;
        // handle the release of the underlying pointer
        if (mPointer) delete mPointer;
        mPointer = other.mPointer;  
        std::cout <<"Assign smart pointer at "<<static_cast<const void*>(other.mPointer)<<std::endl;
        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
};
#endif // __SMARTPOINTER_H__

Test code sptestcase2.cpp

/*
* file name : sptestcase2.cpp
* desp : smart pointer test code case2 to test the copy and assignment of smart pointers
*/

#include <iostream>
#include "smartpointer.h"
class SomeClass{
public:
    SomeClass(){std::cout << "SomeClass default constructor !"<<std::endl;}
    ~SomeClass(){std::cout << "SomeClass deconstructor !"<<std::endl;}
};

void testcase2(void)
{
    // First create a smart pointer, and then assign a value to the created smart pointer
    SmartPointer<SomeClass> spclass1 = new SomeClass;
    std::cout << std::endl;
    // self assignment
    spclass1 = spclass1;
    std::cout << std::endl;

    // Create another smart pointer that points to the same memory resource as the previous pointer
    SmartPointer<SomeClass> spclassother = spclass1;
    std::cout << std::endl;

    // First create a smart pointer, and then use another smart pointer to assign a value to the created smart pointer
    SmartPointer<SomeClass> spclass2 = new SomeClass;
    std::cout << std::endl;
    spclass2 = spclass1;
    std::cout << std::endl;
}

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

Result analysis


  • Insufficient v2 version
Although we can avoid the phenomenon of object resource leakage when sharing the underlying resources between multiple smart pointers by implementing the assignment operator and the copy constructor, there are still some problems when releasing smart pointers: that is, when there are multiple smart pointers executing the same When releasing a piece of underlying resource, each pointer will release the underlying resource once, which causes the final double free error.


2. Knowledge point checking and filling vacancies

//Copy constructor, the object does not exist, initialize it with another object
A a;
A b=a;

//Assignment function, the object exists, assign it with another object
A a;
A b;
b=a;
  • The implementation of the assignment operator needs to solve two problems:
  1. Release of the underlying pointer: This problem is why we need to implement the assignment operator by ourselves. Our solution is to release the original pointer before assigning a new value to the underlying pointer.
  2. Self-assignment: would cause problems with our solution to problem 1. When self-assignment, mPointer and other.mPointer will point to the same memory object, so according to the above solution for problem 1, finally our smart pointer will point to a piece of freed memory. Take the classic solution.
// release the underlying pointer
if (mPointer) delete mPointer;  
mPointer = other.mPointer;
// the case of self-assignment
SmartPointer<SomeClass> spclass = new SomeClass;
spclass = spclass;
//The classic way to solve the self-assignment problem
if (this == &other)
   return *this;
  • header and source files

Header files: prevent repeated precompilation. Multiple cpp files reference this header file, no error occurs

#ifndef HEAD_H
#define HEAD_H
...
#endif
Source files: Multiple cpp files are compiled to generate obj files and then linked.

Guess you like

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