Utilities (1): Implementation of auto_ptr in STL and understanding of auto_ptr_ref

Source: Internet
Author: User

Auto_ptr source code, refer to the C ++ standard library

/* The following code example is taken from the book * "The C++ Standard Library - A Tutorial and Reference" * by Nicolai M. Josuttis, Addison-Wesley, 1999 * * (C) Copyright Nicolai M. Josuttis 1999. * Permission to copy, use, modify, sell and distribute this software * is granted provided this copyright notice appears in all copies. * This software is provided "as is" without express or implied * warranty, and with no claim as to its suitability for any purpose. *//* class auto_ptr * - improved standard conforming implementation */namespace std {    // auxiliary type to enable copies and assignments (now global)    template<class Y>    struct auto_ptr_ref {        Y* yp;        auto_ptr_ref (Y* rhs)         : yp(rhs) {        }    };    template<class T>    class auto_ptr {      private:        T* ap;    // refers to the actual owned object (if any)      public:        typedef T element_type;        // constructor        explicit auto_ptr (T* ptr = 0) throw()         : ap(ptr) {        }        // copy constructors (with implicit conversion)        // - note: nonconstant parameter        auto_ptr (auto_ptr& rhs) throw()         : ap(rhs.release()) {        }        template<class Y>        auto_ptr (auto_ptr<Y>& rhs) throw()         : ap(rhs.release()) {        }                // assignments (with implicit conversion)        // - note: nonconstant parameter        auto_ptr& 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;        }                // destructor        ~auto_ptr() throw() {            delete ap;        }        // value access        T* get() const throw() {            return ap;        }        T& operator*() const throw() {            return *ap;        }        T* operator->() 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 with auxiliary type to enable copies and assignments         */        auto_ptr(auto_ptr_ref<T> rhs) throw()         : ap(rhs.yp) {        }        auto_ptr& operator= (auto_ptr_ref<T> rhs) throw() {  // new             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());        }    };}

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

Auto_ptr_ref:

Auto_ptr is currently the only smart pointer in the C ++ standard. It is mainly used to automatically manage the memory resources pointed to by pointers. Resource management is an important part of programming. Resource is a broad concept in computers. It is used to indicate a limited number of items in a program that must be returned after use. For example, a common mutex lock), file pointer, Win32 paint brush )......, Among them, memory (memory) is the most common kind of resource, which is also the first kind of resource we use most. Therefore, its position is crucial. To what extent is its position important? There are two completely different ideas:

1. memory resources are so important that we cannot give them to computers for management, but must be managed by programmers.

2. memory resources are so important that we cannot give them to programmers for management, but must be managed by computers.

Java, C #, and Eiffel adhere to the second philosophy and hand over memory resources to computer management, which avoids a large number of errors that programmers can easily make in memory management and improves the overall development efficiency, however, it is at the cost of a certain execution time. Therefore, these languages are used in real-time systems, operating systems, language compilers ...... And so on.

C language adheres to the first concept, and C ++ inherits this concept, so that memory resource management is handed over to programmers, of course, they are given more flexibility and can work out exquisite works of art. However, memory management is the root cause of troubles for beginners and C programmers who are not so high, what they bring is not flexibility, but a lingering series of nightmares. For example, memory leakage (Memory Leak) and wild pointer (wild pointer) may cause some very difficult bugs. The final debugging may make us feel the end of the world. [NOTE 1]

Note 1: Isn't there a joke? The real programmer uses C (or C ++). I think it is quite difficult. The Memory Management managed by the programmer himself may be an important reason to support this idea. :)

However, C ++ has another option to manage memory (or even resources), that is, smart pointer. Resource Access is initialized) the specific implementation of the concept.

[NOTE 2]

NOTE 2: several new smart pointers, scoped_ptr, scoped_array, shared_ptr, shared_array, and weak_ptr, are introduced in the quasi-standard boost library of C ++, which have many advantages over auto_ptr, interested readers can go to www.boost.org to have a look. Andrei Alexandrescu also specifically uses the policy design in his Loki library to implement a scalable smartptr template. Some of the technologies used in the template are still very valuable. You can go to http://sourceforge.net/projects/low.lib/to download lokiku for reading.

In the standard, auto_ptr is introduced mainly to solve memory resource management, which is a tough monster. However, while solving a problem, it will also bring about some new problems. auto_ptr itself has the ownership transfer (transfer) problem, and it does not support "value) semantic Concept [NOTE 3]. Therefore, it cannot be used as an element in STL containers. In a newer compiler, if it is used in this way, the compiler will block you. However, if you use it in a slightly older compiler, it is likely to be compiled without any waves. During the execution process, I congratulate you, You are streaking in a very long minefield, the probability that the data can pass without loss is only known in days. :)

Note 3: For details about these concepts, refer to my 2D plane of paradigm.

The correct use of auto_ptr itself is explained in detail and examples in many books, and we can also directly read the source code of auto_ptr to get a more intuitive feeling. So I don't want to waste any time or ink on using it. In auto_ptr's current implementation [Note 4], we will see a strange class template auto_ptr_ref, when I read the C ++ standard library for the first time, I was puzzled when I saw auto_ptr. To be honest, this book is very clear and easy to understand, however, I think the pen and ink in the auto_ptr place is coorse and I have not fully explained the problem. In addition, I have read many books and articles that have not explained this auto_ptr_ref question in detail. Today I want to discuss this in depth and hope I can give a reference to it.

Note 4: there were some bugs in the early implementation of auto_ptr. Later, niclai M. josutis fixed the bug and made an implementation. You can go to http://www.josutis.com/libbook/util/autoptr.hpp.html. Readers are better at reading articles against the code. I have not explained the member function templates. Many books have them, mainly to solve conversions between pointers, especially for Polymorphism pointers.

Auto_ptr_ref converts a value into a reference, just like its name. Specifically, it converts a right value (Rvalue) into a left value (lvalue ). [Note 5] We may be surprised when Will C ++ still need this function? Unfortunately, this function is required to ensure correct behavior and security of auto_ptr.

Note 5: What is the left value and the right value? There are many confusing and unclear concepts. I will express my point of view in the next article.

We all know that when auto_ptr is performing a copy operation (assignment operator and copy constructor), the ownership of the resource will be transferred, that is, the memory resource pointed to by the original auto_ptr is transferred to the new auto_ptr, which itself is empty. Therefore, auto_ptr does not support "value Semantics", that is, the copied value will not change. An example may better illustrate the problem:

Auto_ptr <int> AP1 (New int (9); auto_ptr <int> AP2 (AP1); // AP1 loses ownership and now points to null, AP2 now obtains the 9-point memory resource AP1 = AP2; // AP2 loses ownership and now points to null. AP1 now obtains the 9-point memory resource

When we observe the implementation of assignment operator and copy constructor of auto_ptr, we can also find that its parameter is auto_ptr & RHS, rather than auto_ptr const & RHS [Note 6 ]. That is to say, when auto_ptr performs a copy operation, its argument must be a changeable left value (the fact is that this value must be changed ).

Note 6: You may not get used to this writing method. It is actually const auto_ptr & RHS. Why should I use this writing method? refer to my book "C's tricks (below)". I knew that I was not trying to be unconventional. :)

Most often, the parameter types of the copy operation are referenced to the constant (reference to const), which is exactly to avoid changing the passed arguments (argument ). Since the referenced value is not changed, the C ++ standard stipulates that a constant reference can reference the right value. For example, the following code is valid:

Int const & rI = 60; // 60 is the right value list <int> const & RL = List <int> (); // list <int> () is the right value of int fun (){...}; Int const & Rf = fun (); // fun () is the right value

However, the right value cannot be referenced in general references (non-constant references. For example, the following code is invalid:

int& ri = 60;list<int>& rl = list<int>();int fun(){…}; int& rf = fun();

In auto_ptr, the parameter type of its copy operation happens to be non-constant reference. Therefore, it cannot be correctly handled in the following situations.

Auto_ptr <int> AP1 = auto_ptr <int> (New int (8); // a temporary right value auto_ptr on the right side of the equal sign case1 <int> fun () {// a source function that generates auto_ptr <int>
Return auto_ptr <int> (New int (8);} auto_ptr <int> AP2 (fun (); // case 2 call fun () the generated auto_ptr <int> is the right value.

Note: For Case 1, auto_ptr & operator = (auto_ptr & RHs) or template <class Y> auto_ptr & operator = (auto_ptr <Y> & RHs) will be called ). However, according to the C ++ language, the reference cannot point to a temporary object, unless the object is a constant. So case 1 is dangerous .. For case 2, fun () returns an object, which is also a temporary object, auto_ptr (auto_ptr & RHs) or template <class Y> auto_ptr (auto_ptr <Y> &
RHS) the parameter types of both constructors are referenced, so they are not safe.

This situation is not only legal, but also very common. We cannot reject this usage. What should we do? The talented C ++ library designer has already thought of this for us. The auto_ptr_ref is introduced to solve this problem. Observe the bottom auto_ptr implementation code and we will see the following lines:

/* special conversions with auxiliary type to enable copies and assignments */auto_ptr(auto_ptr_ref<T> rhs) throw(): ap(rhs.yp) {}auto_ptr& operator= (auto_ptr_ref<T> rhs) throw() {// new   reset(rhs.yp);   return *this;}template<class Y>operator auto_ptr_ref<Y>() throw(){  return auto_ptr_ref<Y>(release());}

This is the key. For an auto_ptr right value, it is impossible to call normal value assignment operators and copy constructor for it. For example, for statements

auto_ptr<int> ap1 = auto_ptr<int>(new int(8));

First generate the right value of the temporary object auto_ptr <int> (New int (8), and then use the transform function Template

template<class Y> operator auto_ptr_ref<Y>() throw(){ return auto_ptr_ref<Y>(release());};

By auto_ptr <int> (New int (8), first call the member function release (), then, the obtained original pointer generates another temporary object's right value auto_ptr_ref <int> (a pointer pointing to 8 in the dynamic storage area ). Now let's look at another constructor.

auto_ptr(auto_ptr_ref<T> rhs) throw(): ap(rhs.yp) { }

Its Parameter type is not a reference, and it uses the pass value (by value), so it can accept the right value. At this time, call the default copy constructor generated by auto_ptr_ref <int> and use the auto_ptr_ref <int> temporary object's right value as the reference to generate the RHS, then auto_ptr_ref <int> automatically analyzes the right value of the temporary object to end the lifecycle, followed by the AP (RHS. YP.

Colleagues interested in this usage can refer to the STL source code of SGI.

The auto_ptr mechanism helps us convert the right value to the left value. The theoretical basis of this mechanism is a subtle difference between "overload" and "template parameter deduction rules.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.