If you declare the copy constructor and value assignment operator using the member function template, you still need to manually write the common copy constructor and copy operator. Implicit type conversionAlthough smart pointers provide more useful features than normal pointers, there are also some problems. For example, we have a class level:
class Top{};class Middle: public Top{};class Bottom: public Middle{};
A normal pointer can be implicitly converted to a base class pointer by using a derived class pointer:
Top *p1 = new Bottom;const Top *p2 = p1;
However, if it is a smart pointer, for example, we have implementedSmartPtr
, We need to compile the following code:
SmartPtr
p1 = SmartPtr
(new Bottom);SmartPtr
p2 = p1;
Different instances of the same template have no inheritance relationships. In the compiler's opinionAutoPtr
AndAutoPtr
Are two completely different classes. Therefore, there is a problem with directly compiling the above Code.
Overload ConstructorTo supportSmartPtr
InitializationSmartPtr
, We need to reloadSmartPtr
Constructor. In principle, we need to write as many reload functions as there are classes. Because the class hierarchy is extended, the number of functions to be overloaded is infinite. Then you can introduce the member function template:
template
class SmartPtr{public: template
SmartPtr(const SmartPtr& other);};
Note that this constructor is not declaredexplicit
To use the same style as normal pointers. Normal pointers of child classes can be converted to base class pointers by implicit type conversion.
The constructor that accepts other instances of the same template is called generalized copy constructor ).
Compatibility type checkIn fact, General constructors provide more functions. He canSmartPtr
Implicit conversionSmartPtr
, PutSmartPtr
ConvertSmartPtr
. However, normal pointers do not allow implicit conversions. Therefore, we need to disable them. Note that the implementation of common constructor can solve this problem:
template
class SmartPtr{public: template
SmartPtr(const SmartPtr& other): ptr(other.get()){}; T* get() const{ return ptr; }private: T *ptr;};
Inptr(other.get())
The compiler checks the compatibility of types only whenU
Can be implicitly convertedT
,SmartPtr
Can be implicitly convertedSmartPtr
. This avoids implicit conversion of incompatible pointers.
Other usage methodsIn addition to implicit type conversion, the member function template also has other purposes, such as the value assignment operator .. Below isshared_ptr
Part of the source code:
template
class shared_ptr{public: template
explicit shared_ptr(Y *p); template
shared_ptr
const& r>; template
shared_ptr& operator=(shared_ptr
const& r);};
We can see the normal pointerY*
Toshared_ptr
Declaredexplicit
, Explicit type conversion is required.shared_ptr
Only implicit conversion is required between them. There is a problem when using the copy constructor template: will the compiler generate the default copy constructor? Will a copy constructor be instantiated from your template? That isY == T
Compiler behavior in a scenario.
In fact, the member function template does not change the C ++ rules. C ++ rules: if you do not declare a copy constructor, the compiler should generate one. SoY == T
The copy constructor will not be instantiated from the member function template, but will generate one by itself.
Soshared_ptr
The template also manually declares the copy constructor:
template
class shared_ptr{public: shared_ptr(shared_ptr const& r); template
shared_ptr(shared_ptr
const& r); shared_ptr& operator=(shared_ptr const& r); template
shared_ptr& operator=(shared_ptr
const& r);};