Smart pointers are obviously an attractive part of C ++ and must be mastered. I read C ++ primer, which focuses on the implementation of smart pointers.
The book says:
"HasPtr (Note: it is a custom smart pointer) has the same behavior as a normal pointer in other aspects. Specifically, when copying an object, the copy object and the original object will point to the same basic object. If a basic object is changed through a copy, the value accessed through another object will also change.
The new HasPtr class requires an destructor to delete pointers. However, destructor cannot delete pointers unconditionally ."
The condition is the reference count. If the object is referred to by two pointers, deleting one of the pointers does not call the destructor of the pointer, because another pointer points to the object. It seems that smart pointers mainly prevent improper destructor and suspension pointers.
[Cpp]
Class U_Ptr {
Friend class HasPtr;
Int * ip address;
Size_t use;
U_Ptr (int * p ):
Ip (p), use (1 ){
Cout <"U_ptr constructor called! "<Endl;
}
~ U_Ptr (){
Delete ip;
Cout <"U_ptr distructor called! "<Endl;
}
};
There is a variable use and pointer ip: use records the number of HasPtr objects in the * ip object. Assume that another two HasPtr objects p1 and p2 point to U_Ptr. Now, when I delete p1, the use variable will be automatically reduced by 1, and the U_Ptr will not analyze the structure, so the U_Ptr points to the object will not be destructed, so p2 still points to the original object, and will not become a floating pointer. When delete p2 is used, the use variable is reduced from 1 to 0. In this case, the U_Ptr object is destructed, and the object pointed to by U_Ptr is also destructed to ensure that the memory will not be leaked.
For classes that contain pointers, pay special attention to replication control because only the addresses in the pointers are copied instead of the objects pointed to by the pointers.
Most C ++ classes use one of the three methods to manage pointer members.
(1) No matter the pointer member. Only the pointer is copied. When a pointer releases the space of the object to which it points, other pointers become floating pointers. This is an extreme
(2) When copying, that is, copying the pointer and copying the object pointed to by the pointer. This may cause a waste of space. Because the copying of objects pointed to by pointers is not necessarily necessary.
(3) The third is a method of compromise. A helper class is used to manage pointer replication. The original class has a pointer pointing to the helper class. The data member of the helper class is a counter and a pointer (pointing to the original) (this is the smart pointer implementation method ).
In fact, the reference count of smart pointers is similar to java's garbage collection mechanism: java's garbage determination is very simple. If an object is not referenced, this object is garbage. The system can be recycled.
[Cpp]
# Include
Using namespace std;
Class U_Ptr {
Friend class HasPtr;
Int * ip address;
Size_t use;
U_Ptr (int * p ):
Ip (p), use (1 ){
Cout <"U_ptr constructor called! "<Endl;
}
~ U_Ptr (){
Delete ip;
Cout <"U_ptr distructor called! "<Endl;
}
};
Class HasPtr {
Public:
HasPtr (int * p, int I ):
Ptr (new U_Ptr (p), val (I ){
Cout <"HasPtr constructor called! "<" Use = "<ptr-> use <endl;
}
HasPtr (const HasPtr & orig ):
Ptr (orig. ptr), val (orig. val ){
++ Ptr-> use;
Cout <"HasPtr copy constructor called! "<" Use = "<ptr-> use
<Endl;
}
HasPtr & operator = (const HasPtr &);
~ HasPtr (){
Cout <"HasPtr distructor called! "<" Use = "<ptr-> use <endl;
If (-- ptr-> use = 0)
Delete ptr;
}
Int * get_ptr () const {
Return ptr-> ip address;
}
Int get_int () const {
Return val;
}
Void set_ptr (int * p) const {
Ptr-> ip = p;
}
Void set_int (int I ){
Val = I;
}
Int get_ptr_val () const {
Return * ptr-> ip address;
}
Void set_ptr_val (int I ){
* Ptr-> ip = I;
}
Private:
U_Ptr * ptr;
Int val;
};
HasPtr & HasPtr: operator = (const HasPtr & rhs) {// Note: here, the value assignment operator adds the rhs Usage Technology 1 before reducing the number of operations used, this prevents self-assignment.
++ Rhs. ptr-> use;
If (-- ptr-> use = 0)
Delete ptr;
Ptr = rhs. ptr;
Val = rhs. val;
Return * this;
}
Int main (){
Int * pi = new int (0 );
HasPtr x hpa = new HasPtr (pi, 100 );
HasPtr * hpb = new HasPtr (* hpa );
HasPtr * hpc = new HasPtr (* hpb );
HasPtr hpd = * hpa;
Cout Hpc-> set_ptr_val (10000 );
Cout Hpd. set_ptr_val (10 );
Cout Delete hpa;
Delete hpb;
Delete hpc;
Cout Return 0;
}
The value assignment operator here is troublesome, and I want to analyze it using charts:
Assume that another two smart pointers are p1 and p2, one pointing to the memory with the content 42, and the other pointing to the memory with the content 100, for example:
Now, I want to assign values, p2 = p1. Compared with the above
[Cpp] view plaincopy HasPtr & HasPtr: operator = (const HasPtr & rhs)
In this case, rhs is p1. First, add the use of the ptr to which p1 points to 1, [cpp] view plaincopy ++ rhs. ptr-> use;
Then, do:
[Cpp]
If (-- ptr-> use = 0)
Delete ptr;
Because the object that p2 points to is not pointing to at present, the object will be missing a pointer, so use will perform auto-minus 1;
The condition is true. Because u2's use is 1. Then, run the U_Ptr destructor, and in the U_Ptr destructor, perform the delete ip operation. Therefore, the memory is released without memory leakage.
The following operations are natural and do not need to be repeated:
[Cpp]
Ptr = rhs. ptr;
Val = rhs. val;
Return * this;
After the assignment is completed, it becomes as shown in. The red mark is the changed part:
Note that when you overload the value assignment operator, you must check your self-assignment status.
:
In this case, perform the p1 = p1 operation. First, the u1.use auto increment value is 1, which is 2. Then, the u1.use auto increment value is 1. Then the delete operation will not be executed, and the remaining operations will be smooth. According to C ++ primer, "This value assignment operator adds 1 to the rhs usage count before reducing the Count used by the left operand, thus preventing the assignment by itself ". Well, I understand it that way. Of course, you can do the following as usual:
[Cpp]
If (this = & rhs)
Return * this;
Running result:
U_ptr constructor called!
HasPtr constructor called! Use = 1
HasPtr copy constructor called! Use = 2
HasPtr copy constructor called! Use = 3
HasPtr copy constructor called! Use = 4
0 0
10000 10000
10 10
HasPtr distructor called! Use = 4
HasPtr distructor called! Use = 3
HasPtr distructor called! Use = 2
10
HasPtr distructor called! Use = 1
U_ptr distructor called!