1. Implementation version v2
- copy constructor
- assignment operator function
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
2. Knowledge point checking and filling vacancies
- Copy Constructor and Assignment Function: Difference Between Constructor/Copy Constructor/Assignment Function
//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:
- 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.
- 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 ... #endifSource files: Multiple cpp files are compiled to generate obj files and then linked.