C ++ depth exploration series: smart pointer [1]

zhaozj2021-02-16  55

Subject index:

First, analyze C standard library smart pointer (std :: auto_ptr) 1.Do you smart pointer? 2.std :: auto_ptr Design principle 3.std :: auto_ptr Advanced User Guide 4. Do you think std :: auto_ptr is not enough? perfect?

Second, C conditions, find a strategy for constructing more powerful smart pointers 1. Support for a number of design strategies for reference score 2. Support to process multiple resources 3. Support SubClassing 4. Support for multithreading conditions, thread security A variety of design strategies 5. Other special requirements, re-construct

Third, Generic Programming Basic Technology and Smart Pointer 1. Looking back to Traits Technology in Resources 2. Looking back over multithreaded support

Fourth, COM implementation, Smart Pointer design principle

V. Status of Smart Pointer in the famous C library (standard and non-standard)

-------------------------------------------------- -------------------

First, analyze C standard library smart pointer (std :: auto_ptr) 1.Do you smart pointer? Smart Pointer, Chinese name: smart pointer, shipping? It is undeniable, resource leaks, once a big nightmare for C programs. Garbage Collection (Garbage Collection) is very eye-catching. However, the garbage automatic recycling mechanism does not meet the instantaneous and visibility of memory management, often makes the proud programmer feel uncomfortable. Moreover, C implementation does not introduce this mechanism In the exploration, C programmers have created sharp "Smart Pointer". A certain extent, solving resource leakage problems.

Perhaps, often, you will write this code: // x intend to Class: // Class X {// public: // int m_idata; // public: // x (int m_paramin): m_idata (m_paramin) { } // void print () {cout << m_idata << Endl;} // .....//} // void fook () {x * m_ptrx = new a (m_paramin); m_ptrx-> dosomething () ; // # 2 delete m_ptrx;}

Yes, there may be no problem here. You can guarantee that you will not forget DELETE M_PTRCLASSOBJ in complex, N row, m_ptrclassobj, you will notify you don't forget DELETE M_PTRCLASSOBJ? In life, we often don't have too many Oral guarantee, we need to do something that is really useful. There is also a more sensitive question: exception. If the execution period is abnormal, the function is terminated, then the object of New is leaked. So, you may Will say: So capture an exception to ensure good security. You write such a program:

Void fook () {a * m_ptrx = new a (m_paramin); try {m_ptrx-> dosomething ();} catch (..) {delete m_ptrx; throw;} delete m_ptrx;} Oh! God! Imagine, you Whether it is designed to capture an exception. One day, some people give you recommendations: "It is safe.". You can write your program like this: void fook () {auto_ptr m_smptrx (new x (m_paramin)); m_smptrx-> dosomething ();

OK! You don't believe it. Don't use DELETE? Yes. Don't use it all day to ask yourself: "Is I all DELETE?", And more secure than your delete strategy.

Then, someone tells you that can be used: ok1. Auto_ptr m_smptr1 (new x (m_paramin)); auto_ptr m_smptr2 (m_smptr1); // # 2 May Be you can code # 2 Like this: Auto_PTR m_smptr2; m_smptr2 = m_smptr1; ok2. Auto_Ptr m_smptr1 (new int (32)); OK3. Auto_ptr1 = Auto_Ptr1; m_smptr1 = auto_ptr (new int>); Auto_ptr1 (AUTO_PTR ); OK4. Auto_Ptr m_smptr1 (new x (m_paramin)); m_smptr1.reset (new x (m_paramin1)); ok5. auto_ptr m_smptr1 (new x (m_paramin)); auto_ptr m_smptr2 (m_smptr.release ()); cout << (* m_smptr2) .m_idata << end1; ok6. auto_ptr Fook () {Return Auto Fook () {Return Auto > (new int (100));} OK7 ............. And so on but cannot use: no1. char * chrray = new char [100]; strcpy (chrrray, "i am Programming. "); Auto_Ptr Char *> M_SMPTRCHRPTR (ChRARRAY); // Auto_PTR does not help you manage array resources NO2. Vector ); // Auto_PTR is not suitable for STL content. NO3. const auto_ptr m_smptr1 (new x (100 )); Auto_ptr m_smptr (new x (200)); NO4. X m_objx (300); auto_ptr m_smptr (& m_objx); NO5 x * m_ptr = new x (100); auto_ptr m_smptr = m_ptr; no6 ........ And so ON pre-refers to the problem of ownership so that you can take questions below?

Power1. auto_ptr1 (new x (100)); auto_ptr2-> m_smptr2 = m_smptr1; m_smptr2-> print (); // Output: 100. m_smptr1-> print (); //!! illegal. Power2. auto_ptr m_smptr (new x (100)); auto_ptr returnfun (auto_ptrin) {return m_smptrin;} auto_ptr = returnfun (m_smptr); // # 5

// In the top # 5, I want to tell you that the object ownership is transferred twice. / / What is the object ownership? 2. Std :: auto_ptr Design principle The above correct usage, what are they doing? Illegal, what is the crime? What is the right to transfer, what is the internal wit? Oh! A fog? Let's draw on the realization mechanism. Basic knowledge: a. Smart pointer key technology: Tunctional stack The life of the object controls the life of the objects that constructs on the pile. Because the pointer of the object is stored inside the smart pointer, the delete behavior is called in the paxy function. The general mechanism is as follows: x * m_ptrx = new x (100 ); // # 1 Template auto_ptr; // Maintain pointer to the heap object, after the Auto_PTR is positioned .... // It should point to the object constructed from # 1, ie ownership . ~ Auto () {delete m_ptr;} ....} b. Ownership Transfer said that there is a illegal program fragment as follows: auto_ptr m_smptr1 (new x (100)); auto_ptr m_smptr2 = m_smptr1 ; M_smptr2-> print (); // output: 100. M_smptr1-> print (); // !! illegal. According to the normal system, m_smptr-> print (); how is illegal? That is because of the original , M_SMPTR1 maintenance pointing to New X (1 00) The pointer, but m_smptr2 = m_smptr1; auto_ptr internal mechanism causes m_smptr1 to pass the object's address to m_smptr2, and press your object finger to 0. So natural m_smptr-> print (); fail. Here the program designer should bear Obvious responsibilities. So why AUTO_PTR adopts such a policy: guarantee the singleness of ownership. System security. If multiple full-powered auto_ptr maintains an object, then when you eliminate AUTO_PTR, it will cause multiple auto_ptr Potential danger. Below we are designed as samples (removed unrelated analysis macro), we are designed as samples (off-related macro) to analyze its principles. # 1 Template class auto_ptr {# 2 private: # 3 _tp * _m_ptr; / / Define pointers that will maintain a stack object

# 4 public: # 5 typedef _Tp element_type; // related type definition # 6 explicit auto_ptr (_Tp * __p = 0) __STL_NOTHROW: _M_ptr (__ p) {} # 7 auto_ptr (auto_ptr & __a) __STL_NOTHROW: _M_ptr (__ a.release () ) {} # 8 Template auto_ptr (auto_ptr <_tp1> & __a) __stl_nothrow: _m_ptr (__ a.release ()) {} // # 6, # 7, # 8 is the three versions of the auto_ptr constructor. // # 6 Note: Incoming the pointer to the object, constructs auto_ptr.explicit keyword: Idle Implicit conversion. // This is the correct reason for OK2, and NO5 (implicit conversion) error. // # 7 Note: Copy construct Function. // Introduction to Auto_PTR instance, construct auto_ptr. OK1, OK3 use this configuration. // It is a critical constructor, in specific case, we will analyze // # 8 Note: AUTO_PTR Template member Special functions can be achieved on the basis of inheritance object overload. // // Example: // Class a {public: // virtual void fook () {cout << "i amprogramming" << endl; // / *..............}; // Class B: Public a {// virtual void fook () {cout << "i am working" << endl; // /*...........*/}; // auto_ptr m_smptra (new a (33)); // Substance: // Auto_Ptr m_smptrb ( m_smptra); // The pointer of the base class can assign a pointer to the derived class // // auto_ptr m_smptrb (new b (44)); // Substance: // Auto_PTR m_smptra (m_smptrb); // Detected class pointer can not be assigned pointer // // auto_ptr m_smptra (new b (33)); // ok! // m_smptra-> fook () will call Fook () / / M_smptra-> a :: fook () will call the Fook () // // Auto_Ptr m_smptrb (new a (33)) of the base class A;

// wrong! /// # 9 auto_ptr & operator = (auto_ptr & __a) __stl_nothrow {# 10 if (& __ a! = this) {delete _m_ptr; _m_ptr = __a.release ();} # 11 return * this; # 12} # 13 Template # 14 auto_ptr & operator = (auto_ptr <_tp1> & __a) __stl_nothrow {# 15 i (__a.get ()! = This-> get ()) {delete _m_ptr; _m_ptr = __a.release );} # 16 return * this; # 16} // / / / / / / / / / ); Release operation, detailed code See # 20 ~~ # 23. // Used for * this to get an assigned object, // and put the original maintenance Auto_PTR blank. // NO3 uses the first assignment. // Transfer is _A.RELEASE () results. # 17 ~ auto_ptr () __stl_nothrow {delete _m_ptr;} // Content function. Eliminate objects. Note that the requirements for objects! # 17_tp & operator * () const __stl_nothrow { Return * _m_ptr;} # 18 _tp * Operator -> () const __stl_nothrow {return _ M_PTR;} # 19 _tp * get () const __stl_nothrow {return _m_ptr;} // // Operator overload. // # 17 Note: Promoting operation (Dereference), get an object. See ok5 usage. // # 18 Note: Member operator overload, return to the object pointer. // # 19 Note: Ordinary member function. Act as overload-> operator // # 20 _t * release () __stl_nothrow {# 21 _tp * __tmp = _m_ptr; # 22 _m_ptr = 0; # 23 return __tmp;} // has been detailed above # 24 void reset (_tp * __p = 0) __stl_nothrow {# 25 delete _m_ptr; # 26 _m_ptr = __p;} // Incoming object pointer, change auto_ptr maintenance Object // and forced Auto_PTR to eliminate objects // see OK3 usage.

// According to the C standard, these conversions are required. Most // present-day compilers, however, do not enforce that requirement --- and, // in fact, most present-day compilers do not support the language // FEATURES THAT THESE CONVERSITIONS RESELY ON. // This clip is used for type conversion, there is currently no compiler support // The specific technical details do not respond. # ifdef __sgi_stl_use_auto_ptr_conversions

# 27 private: # 28 template # 29 struct auto_ptr_ref {_tp1 * _m_ptr; auto_ptr_ref (_tp1 * __p): _m_ptr (__ p) {}};

# 30 public: # 31 auto_ptr (auto_ptr_ref <_Tp> __ref) __STL_NOTHROW: _M_ptr (__ ref._M_ptr) {} # 32 template # 33 operator auto_ptr_ref <_Tp1> () __STL_NOTHROW # 34 {return auto_ptr_ref <_Tp> ( this-> release ());} # 35 template operator auto_ptr <_Tp1> () __STL_NOTHROW # 36 {return auto_ptr <_Tp1> (this-> release ());} # 37 #endif / * __SGI_STL_USE_AUTO_PTR_CONVERSIONS * / # 38}; ok! That's it. As the above introduction, you need to face two major characteristics: 1. Conformalize the life of the stack object to control the life of the objects on the stack. 2. By Release guarantee auto_ptr Objects' indefiniteness. On our way to source analysis, you will see where: NO series error? NO1. We see the terminating function Template ~ auto_ptr () _stl_nothrow {delete _m_ptr;} so it You cannot maintain arrays, maintain arrays need to operate: delete [] _M_Ptr; NO2. True section vector and auto_ptr code: a. Feed auto_ptr code auto_ptr (auto_ptr & __a) __stl_nothrow: _m_ptr (__ a.Release ()) {} b. Mention vector Code Part1: void push_back (const _Tp & __x) {if (_M_finish = _M_end_of_storage!) {Construct (_M_finish, __x); _ M_finish;} else _M_insert_aux (end (), __x);} Part2: template Inline void construct (_t1 * __p,

// // Const_T2 & __Value) { // // New (__P) _T1 (__ value); // } Part3. Template void vector <_tp, _alloc> :: _ m_insert_pax (item __position,

// // Const_TP & __X) // {IF (_M_FINISH, * (_ M_FINISH - 1)); _ M_Finish ;

// //_TP __X_copy = __x; //

copy_backward (__ position, _M_finish - 2, _M_finish - 1); * __ position = __x_copy;} else {const size_type __old_size = size (); const size_type __len = __old_size = 0 2 * __old_size:!? 1; iterator __new_start = _M_allocate (__ len ); iterator __new_finish = __new_start; __STL_TRY {__new_finish = uninitialized_copy (_M_start, __position, __new_start); construct (__ new_finish, __x); __ new_finish; __new_finish = uninitialized_copy (__position, _M_finish, __new_finish);} __STL_UNWIND ((destroy (__ new_start, __new_finish), _M_deallocate (__ new_start, __ len))); destroy (begin (), end ()); _M_deallocate (_M_start, _M_end_of_storage - _M_start); _M_start = __new_start; _M_finish = __new_finish; _M_end_of_storage = __new_start __len;}} from the extract VECTOR code, PART1 can be seen, Push_Back's operation behavior. The soldiers are divided into two ways, but then look down, you will find that there is no exception, all through constell TP & Copy behavior, then send a field from the fragment raised from Auto_Ptr. But you know, auto_ptr always insists on object index. That must modify the object of maintenance, and the vector behavior requires const_tp &, so natural meeting Generate problems. General compilers can find such errors.

In fact, all containers in STL use const _tp & strategy. // Two articles in Sutter and Josuttis are mentioned: STL container does not support auto_ptr reasons The object of COPY is just a object of ownership, This object does not conform to the requirements of STL. But I always feel that it is not a real copy object, but I use Vector > The purpose is to maintain the object Don't care so-called complete object. And I used my own Smart Pointer to work with the STL container, is very normal. That need to be noticed only const questions. // NO3. This is also caused by auto_ptr implicitly ownership issues. Const auto_ptr is not allowed to be modified. Just mention: Const object does not mean that the object is not changed. Under the two const semanties, there is a way to modify the object or Objects or other resources maintained by object internal pointer. NO4. Look at Auto_PTR. Delete does not eliminate resources on the stack.

NO5. The constructor that rely on the incoming object pointer is declared as explicit, disable implicit conversion.

3.Auto_ptr Advanced User Guide A. Class member Auto_PTR, disable constructor to build "full object" Program1: struct structX {int m_idata; char m_chrdata; / * and so on * /}; for object programming, we will Structx playing parcel: class StructWrapper {private: Structx * m_STRTxptr; public: StructWrapper (): m_STRTxptr (new Structx) {} ~ StructWrapper () {delete m_SMRTxptr;} public: void Soperator1 () {/ * for Structx object characteristics of operation * /} void Soperator2 () {/ * characteristic operation for Structx object * /} / * and so on * /}; Programme2: class StructWrapper {private: auto_ptr m_SMPTRx; public: StructWrapper (): m_SMPTRAx (NEW STRUCTX) {} public: void Soperator1 () {/ * Feature Operation for Structx Objects * /} Void Soperator2 () {/ * Targeting Features for StructX Objects * /} / * and so on * /}; programme3 : StructWrapper :: StructWrapper (const structwrapper&) : M_smptrx (new struct (* Other.m_smptrx) {} structwrapper & structWrapper :: operator = (const strurator =) {* m_smptrx = * Other.m_smptrx;};

In the need to construct the need to be intelligent maintenance in the heap. We transform the programme1 to Program2: Good, the object is smart to maintain. For the StructWrapper, you will have such a construct or assignment: StructWrapper m_SMPTRWrapper2 (m_SMPTRWrapper1); StructWrapper mSMPTRWrapper2 = m_SMPTRWrapper1; please note: when you calm to a: M_SMPTRWrapper1-> Soperator1 (); when the system crashes Not surprisingly, ownership or ownership ask yourself: when programme2.. When the default copy constructor functions, the default constructor of Auto_PTR is called, then all the default behaviors of Auto_Ptr follows the independent strategy. Yes, this way. M_SmptrWrapper1 object ownership transfer to m_smptrwrapper1-> soperator1 (); then The operation becomes on NULL. Oh! The system does not collapse. Then you need to think that Programme3 uses Auto_Ptr's Promotion Operation to construct "complete object" .b. Use the const keyword to prevent unrecriminal privileges Transfer From above, you can see that all ownership can make a big disaster everywhere. And for general applications, independent security strategy. So we use const to modify auto_ptr, no business Error. Of course, the above mentioned: does not mean that auto_ptr is not modified. In need, from two const semanties, you can achieve modifications.

Of course, you also hope that in the process of passing auto_ptr, then you can pass the reference of Auto_Ptr, then there is no loss: Void Fook (const auto_ptr & m_paramin); uses a reference in the return after returning. You have to use a pointer. Because references, whether as Lvalue or RValuev, construct or assignment functions will be called.

4. Do you think std :: auto_ptr is not perfect enough in practice, std :: auto_ptr can meet your needs? Andrei AlexandRescu mentioned in an article, mentioned: The technology about Smart Pointer is like witchcraft. Smart Pointer As the core of C garbage recovery mechanism, it must be strong enough to have industrial strength and safety. But in order to others, we still need to draft thorns to continue to explore.

Below, on the requirements level, what else we think about? A. Std :: auto_ptr can handle arrays? Can we use smart pointers to manage other resources? For example, a thread handle, a file handle and SO ON! B. Do you really implement an independence policy? C .ur intelligent pointer also needs to play power on inheritance and virtual levels! d. Often, you need to extend the function of the OUR smart pointer to meet the dynamics Need! E. Maybe, there are still many.

-------------------------------------------------- ------------- [Continue]

Second, C conditions, find a strategy for constructing more powerful smart pointers 1. Support for a number of design strategies for reference score 2. Support to process multiple resources 3. Support SubClassing 4. Support for multithreading conditions, thread security Multiple design strategies 5. Other special requirements, thus three, Generic Programming Basics and Smart Pointer 1. Looking back to TRAITS technology in resource 2. Back to multithreaded support

Fourth, COM implementation, Smart Pointer design principle

V. Status of Smart Pointer in the famous C library (standard and non-standard)

-------------------------------------------------- ---------

-------------------------------------------------- ------------ Solemn statement: Allow copy, modification, delivery or other behavior but is not allowed for any commercial use. Writing 20/3/2003 Last modified: 20/3/2003 by redstar81 81_redstar@163.com--------------------------------------------- ----------------


New Post(0)