Auto_ptr is a smart pointer provided in the current C + + standard library, admittedly, auto_ptr is so unsatisfactory that programmers have to use it very carefully, as with "bare" pointers, to ensure that there is no error. That it can't even apply to so many containers and algorithms in the same standard library, but even so, we still can't deny the value and idea of this little auto_ptr.
Here is a auto_ptr version written by Nicolai M. Josuttis (<<the C + + standard library>> author), and made a few formatting changes to make it easy to analyze and read.
Namespace std{Template<class t> class Auto_ptr {private:t* ap; Public://constructor & destructor-----------------------------------(1) explicit auto_ptr (t* ptr = 0) throw (): AP (PTR) {} ~auto_ptr () throw () {delete AP; }//Copy & Assignment--------------------------------------------(2) auto_ptr (auto_ptr& rhs) throw (): AP (RH S.release ()) {} Template<class y> auto_ptr (auto_ptr<y>& rhs) throw (): AP (Rhs.release ()) {} auto_pt r& operator= (auto_ptr& rhs) throw () {Reset (Rhs.release ()); return *this; } template<class y> auto_ptr& operator= (auto_ptr<y>& rhs) throw () {Reset (Rhs.release ()); return *this; }//Dereference----------------------------------------------------(3) t& operator* () const throw () {return *a P } t* operator-> () const throw () {return AP; }//Helper functions------------------------------------------------(4)//value access t* get () consT throw () {return AP; }//Release ownership t* release () throw () {t* tmp (AP); AP = 0; return TMP; }//Reset value void Reset (t* ptr=0) throw () {if (AP! = ptr) {delete ap; AP = ptr; }}//Special conversions-----------------------------------------------(5) template<class y> struct AUTO_PTR_R EF {y* YP; Auto_ptr_ref (y* RHS): YP (RHS) {}}; Auto_ptr (auto_ptr_ref<t> RHS) throw (): AP (RHS.YP) {} auto_ptr& operator= (auto_ptr_ref<t> rhs) throw () {Reset (RHS.YP); return *this; } template<class y> operator auto_ptr_ref<y> () throw () {return auto_ptr_ref<y> (Release ()); } template<class y> operator auto_ptr<y> () throw () {return auto_ptr<y> (Release ()); } };}
1 Constructors and destructors
Auto_ptr Gets the ownership (ownership) of an object at construction time, releasing the object at the time of destruction. We can use AUTO_PTR to improve code security in this way:
int* p = new int (0);
Auto_ptr<int> ap (P);
From then on we don't have to worry about when P should be released, or if there is a memory leak in the event of an exception.
Here are a few things to note:
1) because the auto_ptr will definitely delete the object he owns, all of us have to pay attention to, a radish a pit, two auto_ptr cannot have the same object at the same time. Like this:
int* p = new int (0);
Auto_ptr<int> AP1 (P);
Auto_ptr<int> AP2 (P);
Because AP1 and AP2 both think that pointer p is the tube, and when the destruction attempts to delete p, the behavior of deleting the same object two times is undefined in the C + + standard. So we have to prevent such use of auto_ptr.
2) Consider the following usage:
int* pa = new INT[10];
Auto_ptr<int> ap (PA);
Because the Auto_ptr destructor removes the pointer with delete instead of delete [], we should not use AUTO_PTR to manage an array pointer.
3) The explicit keyword of the constructor effectively prevents the implicit conversion from a "bare" pointer to the AUTO_PTR type.
4) because C + + guarantees that it is safe to delete a null pointer, we do not need to write the destructor:
~auto_ptr () throw ()
{
if (AP) Delete ap;
}
2 Copy Construction and assignment
Unlike reference-counted smart pointers, auto_ptr requires full possession of the "bare" pointer. This means that a "bare" pointer cannot be owned by more than two auto_ptr at the same time. So, in the case of copy construction or assignment, we have to do special processing to ensure this feature. Auto_ptr's practice is "transfer of ownership", that is, the copy or assignment of the source object will lose ownership of the "bare" pointer, so, unlike the generic copy constructor, assignment function, auto_ptr copy constructor, the assignment function parameter is a reference instead of a constant reference (const Reference). Of course, a auto_ptr cannot have more than two "bare" pointers at the same time, so a copy or assignment of the target object will first release its original object.
Here are the points to note:
1) Since a AUTO_PTR has been copied or assigned, it has lost ownership of the original object, and the Auto_ptr (dereference) operation is unsafe at this time. As follows:
int* p = new int (0);
Auto_ptr<int> AP1 (P);
auto_ptr<int> AP2 = AP1;
cout<<*ap1; Error, at this point the AP1 only has a null pointer in hand
This more subtle scenario occurs when Auto_ptr is passed as a function parameter by value, because a local object is generated in the function's scope during the function call to receive the incoming auto_ptr (copy construct), so that the passed-in argument auto_ PTR loses its ownership of the original object, and the object is deleted locally auto_ptr when the function exits. As follows:
void F (auto_ptr<int> ap) {Cout<<*ap;}
Auto_ptr<int> AP1 (new int (0));
f (AP1);
cout<<*ap1; Error, after the F (AP1) function call, AP1 no longer owns any objects.
Because this is too subtle, it's too easy to go wrong, so it's important to avoid auto_ptr as a function parameter by value. Perhaps you might think of using auto_ptr pointers or references as function arguments, but think about it, we don't know what to do with the incoming auto_ptr in the function, and if some of those operations make it lose ownership of the object, it could lead to a fatal execution-time error. Perhaps it would be a good choice to pass auto_ptr in the form of a const reference.
2) We can see that both the copy constructor and the assignment function provide a member template to implement the implicit conversion of the auto_ptr without overwriting the "Orthodox" version. If we have the following two classes
Class base{};
Class Derived:public base{};
The following code can then be used to implement an implicit conversion from auto_ptr<derived> to auto_ptr<base>, because derived* can be converted to a base* type
auto_ptr<base> apbase = auto_ptr<derived> (new derived);
3) Because Auto_ptr does not have value semantics (value semantic), auto_ptr cannot be used in STL standard containers.
The so-called value semantics, refers to a type that meets the following criteria (assuming Class A):
A A1;
A A2 (A1);
A A3;
a3 = A1;
So
a2 = = a1, a3 = = A1
Obviously, Auto_ptr does not meet the above conditions, and we know that the STL standard container uses a large number of copy assignment operations, and assumes that the type of operation must meet the above criteria.
3 withdrawal operation (dereference)
The extraction operation has two operations, one is to return a reference to the object it owns, and the other is to implement a member of the object that it owns by calling Auto_ptr. Such as:
struct A
{
void f ();
}
auto_ptr<a> APA (new A);
(*apa). f ();
Apa->f ();
Of course, we must first make sure that the smart pointer does have an object, otherwise the behavior of the operation is undefined for the extraction of null pointers.
4 Auxiliary functions
1) Get is used to explicitly return an object pointer owned by AUTO_PTR. As we can see, the auto_ptr provided by the standard library does not provide an implicit conversion from the "bare" pointer to the AUTO_PTR (the constructor is explicit), nor does it provide an implicit conversion from auto_ptr to "bare" pointers, which may be less flexible in terms of use. It is worthwhile to consider the security it brings.
2) release, used to transfer ownership
3) Reset, which is used to receive ownership if the AUTO_PTR has already owned an object, the object must be disposed first.
5 Special conversions
Here is an auxiliary class auto_ptr_ref to do a special conversion, according to the standard explanation, the function of this class and the following 4 functions is: allows us to copy and assign value Non-const Auto_ptrs, but cannot copy and assign a const auto_ptrs. I cannot understand the meaning of these two sentences very accurately, but according to our observations and experiments, we should be able to understand that without this code, we could have copied and assigned Non-const's auto_ptr and forbidden copying and assigning const AUTO_PTR functions, Just can't copy and assign temporary auto_ptr (rvalue), and these auxiliary codes provide some conversions that allow us to copy and assign temporary auto_ptr, but do not make const AUTO_PTR can also be copied and assigned value. As follows:
Auto_ptr<int> AP1 = auto_ptr<int> (new int (0));
auto_ptr<int> (new int (0)) is a temporary object, an rvalue, and the generic copy constructor can of course copy the right value, because its parameter category must be a const reference, but we know that auto_ The copy function of PTR has the parameter type reference, so, in order for this line of code to pass, we introduce the auto_ptr_ref to realize the conversion from the right value to the left value. The process is:
1) Ap1 to construct itself by copying auto_ptr<int> (new int (0))
2) auto_ptr<int> (new int (0)) does not match the right value with the existing two copy constructor parameter types and cannot be converted to that type of parameter
3) found auxiliary copy constructor auto_ptr (auto_ptr_ref<t> rhs) throw ()
4) Attempt to convert auto_ptr<int> (new int (0)) to auto_ptr_ref<t>
5) Find the type conversion function operator auto_ptr_ref<y> () throw (), the conversion succeeds, and thus the copy succeeds.
Thus, a copy constructed right value (temporary object) was successfully implemented by an indirect class.
At the same time, this helper method does not cause the const auto_ptr to be copied, because in the 5th step, this type conversion function is Non-const, and we know that the Const object cannot invoke the Non-const member, so the conversion fails. Of course, here's a question to note, assuming that you comment out the code for these auxiliary conversions, the line code is still likely to compile successfully, which is why? Debug, we can see that only one constructor is called, and the copy constructor is not called because the compiler has optimized the code. This type of optimization is called returned value optimization, which can effectively prevent the construction of some meaningless temporary objects. Of course, the premise is that your compiler will support returned value optimization.
Visible, auto_ptr short hundred Line of code, or contains a lot of "mystery".
Effective C + + clause 13-17 "Object Management resources" auto_ptr Source code Analysis