C + + learning problems encountered in the record. Use of the textbook: "C + + Primer."
Smart pointers. What How.
What ' s The Smartpointer and how to impletment it?
What is a smart pointer.
By reference counting, automatically manages the lifetime of dynamically allocated memory, avoiding memory leaks or methods of dangling pointers.
Application Scenario:
If a member of a class is a pointer to a dynamically allocated block of memory, there are two ways to do this when replicating control:
1, the copy pointer to the block of memory, in order to avoid memory leaks, the class in the destructor release memory. This creates a waste of memory space, and the copy operation can also incur unnecessary overhead.
2, only copy the pointer. But a new problem has been introduced: when the memory block is freed by a pointer member of a replica object, the other pointers become so-called dangling pointers.
Smart pointers are introduced here to solve the problems in 2.
How to implement smart pointers.
To solve this problem, in Method 2, we add a reference counting method to manage the memory release of this object.
Suppose what we need to manage here is an int pointer IP pointing to the memory. The following figure:
The u_ptr is used to bind the pointer to a reference count, and the class Hasptr indirectly accesses the IP-pointing memory through a pointer member pointing to the u_ptr.
(Here should be limited, a memory block corresponds to only one U_ptr object)
The U_ptr reference count is initialized to 1.
All copy control operations on objects that are hasptr to the class modify the U_ptr reference count.
Each copy of this Hasptr object does not copy pointer IP to point to the memory block, but to U_ptr's use plus one.
In each object's destructor, it is judged whether use minus one is 0, and if so, destroys the memory block that the U_ptr object binds to.
//c++ Primer plus ... chapter 8 page253 #include <iostream> #include <string> #include
<new> using namespace std;
Class u_ptr{Private:friend class Hasptr;
int *ip;
size_t use; u_ptr (int *p): IP (P), use (1) {}
~u_ptr () {cout << "u_ptr destructor...free mem ip =" << IP << endl;
Delete IP;
}
}; Class hasptr{Public:hasptr (const string &str, int *p): Name (str), PTR (new U_ptr (p)) {cout << name <<
\thasptr do normal construct "<< Endl; } hasptr (const string &str, const hasptr &orig): Name (str), PTR (orig.ptr) {cout << name << "\thasptr"
Do copy construct "<< Endl;
++ptr->use;
}//some friend operators friend std::ostream& operator<< (std::ostream&, const HASPTR &); hasptr& operator= (const hasptr &orig) {cout << name << "\thasptr do assignment from" << orig
. name << Endl;
if (orig.ptr = = this->ptr) {cout << "They are the same one, do nothing" << Endl;
return *this;
} ++orig.ptr->use;
if (--ptr->use = = 0) {cout << name << "\tdelete ptr" << Endl;
Delete ptr; }else {cout << name <<
"\tptr usecnt =" << ptr->use << Endl;
ptr = orig.ptr;
return *this;
} ~hasptr () {--ptr->use;
cout << name << "\thasptr destructor ... ptr usecnt =" << ptr->use << Endl; if (Ptr->use = = 0) {delete ptr;//here call u_ptr ' s destructor}}//some API int * GET_PTR () const {return P
Tr->ip;}
int Get_ptr_val () const {return * (PTR->IP);}
void set_ptr (int *p) {ptr->ip = P;}
void Set_ptr_val (int i) {*ptr->ip = i;}
Private:string name;
U_ptr *ptr;
}; std::ostream& operator<< (std::ostream& os, const hasptr &hp) {os << hp.name << "\tval =" &
lt;< hp.get_ptr_val () << "\taddr =" << hp.get_ptr ();
return OS;
}//overloaded the operator "<<".
int main (int argc, char const *argv[]) {int *a = new int (123);
cout << Endl << "Normal constructor" << Endl;
Hasptr CP1 ("CP1", a);
cout << CP1 << Endl; cout << ENDL << "copy constructor" << Endl;
Hasptr cp2 ("Cp2", CP1);
Cp2.set_ptr_val (199);
cout << cp2 << Endl;
cout << Endl << "assignment operator" << Endl;
CP2 = CP1;
cout << cp2 << Endl;
cout << Endl << "More hasptr to a" << Endl;
Hasptr CP3 ("CP3", a);
Hasptr CP4 ("CP4", a);
cout << CP3 << Endl;
cout << CP4 << Endl;
if (a!=null) cout << "A is still keep the mem, addr =" << *a << Endl;
else cout << "A has been free mem" << Endl;
cout << Endl << "...". Exit from main "<< Endl;;". Delete (a);
Don't need free mem-return 0;
}
Under Linux, compile with g++ and run the results:
Normal constructor
CP1 hasptr do normal construct
cp1 val = 123 addr = 0x9f0d008
Copy Constructor
cp2 hasptr do copy construct
cp2 val = 199 addr = 0x9f0d008
Assignment C12/>CP2 hasptr do assignment from CP1
They are the same, doing nothing
cp2 val = 199 addr = 0x9f0d0
hasptr to a
cp3 hasptr does normal construct CP4 hasptr
do normal construct
CP3 val = 199 addr = 0x9f0d008
cp4 val = 199 addr = 0x9f0d008
A is still keep the mem, addr = 1 It is ....
exit from main
CP4 hasptr destructor ... ptr usecnt = 0
u_ptr destructor...free (+). Mem IP = 0x9f0d008
cp3 hasptr destructor ... ptr usecnt = 0 u_ptr destructor...free
mem ip = 0x9f0d008
CP2 hasptr destructor ... ptr usecnt = 1 cp1 hasptr
destructor ... ptr usecnt = 0
u_ptr destructor ... . free Mem IP = 0x9f0d008