C ++ Depth Exploration Series: Smart Pointer1

zhaozj2021-02-16  83

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 <

<

// .....

//}

//

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 reserve 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 how to use it: 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_PTR M_SMPTR1; M_SMPTR1 = Auto_Ptr (New INT (100)); Auto_Ptr M_SMPTR1 (Auto_PTR (New INT (100))); 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; cout << (* m_smptr2) .m_idata < OK6. Auto_Ptr Fook () {Return Auto (New Int (100));} OK7 ............. And so on but cannot use: no1. char * chrray = new char [100 ]; STRCPY (Chrarray, I am Programming. "); Auto_ptr m_smptrchrptr (chrarray); // Auto_PTR does not help you manage array resources NO2. Vector

m_vecsmptr;

m_vecsmptr.push_back (auto_ptr (new int (100)));

// auto_ptr

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 as to take questions below?

Power1. auto_ptr m_smptr1 (new x (100)); auto_ptr m_smptr2 = m_smptr1; m_smptr2-> print (); // Output: 100. m_smptr1-> print (); //!! illegal.

Power2. auto_ptr m_smptr (new x (100)); auto_ptr _smptrin {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 a 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 Savel 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 points to New x (100) Pointer, However, m_smptr2 = m_smptr1; auto_ptr internal mechanism causes m_smptr1 to pass the address of the object to M_SMPTR2, and set your object to 0. So natural m_smptr-> print (); fail. The program designer should have obvious responsibilities. So why AUTO_PTR adopts such a policy: guarantees the singleness of ownership. System security. If multiple full-powered auto_ptr maintains an object, then when you eliminate AUTO_PTR, it will cause potential dangers of multiple auto_ptr. We design the SGI-STL's auto_ptr designed as a sample (removed unrelated analysis macro), to analyze its principle. # 1 template class auto_ptr {# 2 private: # 3 _tp * _m_ptr; // Define Pointer to maintain the heap 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: The pointer to the object, constructs auto_ptr.explicit keyword: Prohibit implicit conversion. // This is OK2 correct, and the reason for NO5 (implicit conversion) error. // # 7 Note: Copy constructor. // Passing an Auto_PTR instance, constructing this configuration. // It is a very critical constructor, in the specific case, we will analyze // # 8 Note: AUTO_PTR Template member, can inherit On the basis of the object overload, special features are realized. // // Example: // Class a {public: // Virtual void Fook () {cout << "i am programming"

// Class B: Public a {

// Virtual void fook () {cout << "i am working" <

//*...........*/};

// Auto_PTR M_SMPTRA (New A (33)); //

Substance: // Auto_PTR M_SMPTRB (m_smptra); // The pointer of the base class can assign a pointer // // auto_ptr m_smptrb (new b (44)); // substance: // Auto_PTR m_SMPTRA (m_smptrb); / / Delicious pointer does not assign the reference to the base class // Auto_PTR M_SMPTRA (New B (33)); // ok! // m_smptra-> fook () will call the Fook () // m_smptra of derived class B -> 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 IF (__a.get ()! = This-> get ()) {delete _m_ptr; _m_ptr = __a.release ();} # 16 return * this; # 16} // // # 9 ~~ # 16 two A version of the assignment function. // delete _m_ptr; before the assignment, destroy the original maintenance object. // _a.Release () 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. // // / / permissions transfer It is _a.release () results. # 17 ~ auto_ptr () __stl_nothrow} // parsing function. Eliminate objects. Note that the requirements for objects! # 17_tp & operator * () const __stl_nothrow {Return * _M_ptr;} # 18 _t * operator -> () const __stl_nothrow {return _m_ptr;} # 19 _tp * get () const __stl_nothrow {return _m_ptr;} // // operator overload. // # 17 Note: Promotion operation (Dereference), get an object. See OK5 Usage. // # 18 Note: Member operator overload, return to the object pointer. // # 19 Comment:

Ordinary member functions. Role with overload-> operators // # 20 _tp * Release () __stl_nothrow = _m_ptr; # 22 _m_ptr = 0; # 23 return __tmp;} // has detailed ## 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 forcing Auto_PTR to eliminate objects of maintenance ///// 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 Conversions Rely on. // This clip is used for type conversion, and there is currently no compiler support // The specific technical details are not claim.

#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! This way. As the introduction of the above introduction, you need to face two major characteristics: 1. Conformalize the life of the stack object. The life period of the object constructed on the stack 2. By Release to ensure auto_ptr's independence. In our right On the basis of source code analysis, you can see where: no series error? NO1. We see the parsing function template ~ auto_ptr () _stl_nothrow {delete _m_ptr;} So it does not maintain array, maintain arrays need to operate: delete [] _M_ptr; no2. True section Vector and Auto_PTR code: a. 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_AUX (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 STL requirements. But I always feel that it is not a real copy object, but I use the purpose of using the purpose of maintaining the object, not careful so-called The complete object. And I used the Smart Pointer written with the STL container, is very normal. That need to pay attention to the const problem.

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, in two const semanties, there is a way to modify the object or object internal pointer maintenance Objects or other resources. NO4. Look at Auto_PTR 's passion. 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 () {/ * operation with respect to characteristics 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 () {/ * Total Operation for Structx Objects * /} / * and so on * /}; Programme3: StructWrapper: : Structwrapper (const structwrapper & other): m_s MPTRX (NEW STRUCT (* Other.m_smptrx) {} structWrapper & structWrapper :: Operator = (const strurator) {* 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 you can pass auto_ptr's reference in function to pass auto_ptr, then you have no lost: void fook (const auto_ptr & m_paramin); use the reference to use the reference after returning. You have a pointer. Because references, regardless of 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 copying, modification, delivery, or other behavior but is not allowed for any commercial use. Writing 20/3/2003 Last modified: 20/3/2003 Tomhornson @ Hotmail.com --------------------------------- ----------------

转载请注明原文地址:https://www.9cbs.com/read-14660.html

New Post(0)