) Auto_ptr and shared_ptr

Source: Internet
Author: User

Convert from: auto_ptr and shared_ptr --- auto_ptr (1)
Auto_ptr and shared_ptr --- shared_ptr (2)
Suggested steps ~~

This article tries to explain how to use auto_ptr and shared_ptr to make the use and management of dynamically allocated objects safer and more convenient. In addition to the general usage instructions, it mainly describes the similarities and differences between them-the differences between satisfying requirements and overhead. Most of the article's knowledge comes from: 1. predictional C ++ (Herb) Item 37 auto_ptr2. predictional C ++ Style (Herb) and C ++ Coding Standard (Herb, Andrei), some of which discuss the use of shared_ptr 3. source code of GC ++ and VC ++ 8.0 auto_ptr 4. the source code and documentation of the Boost library shared_ptr are both an implementation of smart pointers. The so-called smart pointers usually refer to the following objects: 1. there is a pointer to the dynamically assigned object, which has the right to use and ownership (exclusive or shared) of the object ). 2. Reload * and-> operations. The behavior is the same as the pointer of the owned object. 3. When your life cycle ends, some cleanup actions related to owning objects will be performed. Auto_ptrAuto_ptr is the implementation of a lightweight smart pointer in the standard library, which exists in the header file memory. It is lightweight because it only has one member variable (with the object pointer ), the related call overhead is also very small.

The following code comes from the source code in VC ++ 8.0:

There is a data structure of auto_ptr_ref. We can ignore it. This is only the internal proxy structure used for some implicit const changes. Our client code usually does not use it directly. In addition to constructor, copy constructor, assign value function, destructor, and two overload operators (*,->), get, release, and reset functions are also displayed, their functions are as follows: 1. get, get internal Object Pointer 2. release: discard the ownership of the internal object and set the internal pointer to null. 3. reset: destroys the internal object and accepts the ownership of the new object (if the default parameter is used, that is, there is no ownership of any object)

The following routine comes from predictional C ++ and Item 37:

// Example 2: Using an auto_ptr
//
Void g ()
{
T * pt1 = new T;
// Right now, we own the allocated object
// Pass ownership to an auto_ptr
Auto_ptr <T> pt2 (pt1 );
// Use the auto_ptr the same way
// We 'd use a simple pointer
* Pt2 = 12; // same as "* pt1 = 12 ;"

Pt2-> SomeFunc (); // same as "pt1-> SomeFunc ();"
// Use get () to see the pointer value
Assert (pt1 = pt2.get ());
// Use release () to take back ownership
T * pt3 = pt2.release ();
// Delete the object ourselves, since now
// No auto_ptr owns it any more
Delete pt3;

} // Pt2 doesn't own any pointer, and so won't
// Try to delete it... OK, no double delete
 

// Example 3: Using reset ()
//
Void h ()
{
Auto_ptr <T> pt (new T (1 ));
Pt. reset (new T (2 ));
// Deletes the first T that was
// Allocated with "new T (1 )"

} // Finally, pt goes out of scope and
// The second T is also deleted

 

As shown in the preceding example, the use of auto_ptr is very simple. The constructor has a dynamically assigned ownership of the object, which can then be used as an object pointer. When the auto_ptr object is destroyed, it will also automatically destroy objects with their own ownership (well, the standard RAAI practice). release can be used to manually discard ownership, and reset can be used to manually destroy internal objects. But in fact, auto_ptr is a class that is easily misused and often misused in reality. The reason is that its object ownership is occupied and its non-trivial copy behavior. The object ownership of auto_ptr is exclusive! This makes it impossible for two auto_ptr objects to have ownership of the same dynamic object at the same time, which also results in the copy behavior of auto_ptr being non-equivalent, with the transfer of object ownership. When we carefully observe the source code of auto_ptr, we will find that the parameter types accepted by the copy constructor and the value assignment operator are non-const reference types (auto_ptr <_ Ty> &), instead of the const reference type we should generally use, we will find: auto_ptr (auto_ptr <_ Ty> & _ Right) _ THROW0 ()
: _ Myptr (_ Right. release ())

{// Construct by assuming pointer from _ Right auto_ptr
}
 
Template <class _ Other>
Auto_ptr <_ Ty> & operator = (auto_ptr <_ Other> & _ Right) _ THROW0 ()

{// Assign compatible _ Right (assume pointer)
Reset (_ Right. release ());
Return (* this );
}

 

During the copy process, the Copied object (_ Right) will be called release to discard the ownership of the included dynamic object, and the ownership of the dynamic object will be transferred, the new auto_ptr excludes the ownership of dynamic objects. That is to say, the object to be copied will be modified during the copy process. The object to be copied is equivalent to the object to be copied. This means that the following code is incorrect (the routine comes from Exceptional C ++ Item 37): // Example 6: Never try to do work through

// A non-owning auto_ptr
//
Void f ()
{
Auto_ptr <T> pt1 (new T );
Auto_ptr <T> pt2;

Pt2 = pt1; // now pt2 owns the pointer, and

// Pt1 does not
Pt1-> DoSomething ();

// Error: following a null pointer
}

 

At the same time, do not put auto_ptr into the container of the standard library; otherwise, the copying behavior is not prepared in the standard library container (the copying behavior required by the standard library container is equivalent ), errors that are hard to detect. (Please refer to Exceptional C ++ Item 37 for more information) the special copy behavior of auto_ptr makes it a very dangerous behavior to use it to transmit dynamic objects remotely, in the process of transmission, some auto_ptr objects are left empty but the program itself lacks such cognition. To put it simply, auto_ptr is suitable for managing dynamic objects with short lifecycles or that are not transferred remotely. auto_ptr is used to manage dynamic allocation objects, it is better to be confined to a function or a class. That is to say, the entire process of generating, using, and destroying dynamic objects is in a small controlled range, and will not include some extensions to adapt to the future tense. Shared_ptrShared_ptr is a smart pointer implementation provided by the Boost library, just as its name implies:

An important goal of shared_ptr is to provide a standard shared-ownership pointer.

An important purpose of shared_ptr is to provide a standard smart pointer for shared ownership. -- The Boost library documentation is correct. shared_ptr aims to solve the limitations of auto_ptr on object ownership (auto_ptr is exclusive) and provides intelligent pointers that can share ownership by using the reference counting mechanism, of course, there will be no extra cost ...... First, a shared_ptr object must include a pointer (pn) that references the counter proxy object (shared_count) in addition to a pointer (px) of the object it owns ). This reference counting proxy object includes a real multi-state reference counting object (sp_counted_base) pointer (_ pi ), when using the VC compiler, a real reference counting object includes a virtual table, a virtual table pointer, and two counters. Result is a shared_ptr object. we can clearly see the data contained after it is expanded:

Suppose we have multiple (more than five) shared_ptr shared a dynamic object, then the overhead of each shared_ptr is about 3 or 4 times higher than the overhead of using only native pointers (this is still ideal, ignores the inventory surplus overhead caused by dynamic allocation ). If only one shared_ptr exclusive dynamic object, the space overhead is dozens of times higher! The overhead of auto_ptr is only twice that of the native pointer. The overhead of time is mainly in the initialization and copy operations. the overhead of * and-> Operator Overloading is the same as that of auto_ptr. Of course, the overhead is not the reason we don't use shared_ptr. Never perform immature optimization until the Performance Analyzer tells you this. This is a wise suggestion from Hurb. The above description is just to let you know that the powerful functions are always accompanied by more overhead. shared_ptr should be used, but do not abuse it too much, especially in some areas where auto_ptr is better. The following is the shared_ptr Type Definition: template <class T> class shared_ptr {
 

Public:
 

Typedef T element_type;
 

Shared_ptr (); // never throws

Template <class Y> explicit shared_ptr (Y * p );

Template <class Y, class D> shared_ptr (Y * p, D d );

~ Shared_ptr (); // never throws
 

Shared_ptr (shared_ptr const & r); // never throws

Template <class Y> shared_ptr (shared_ptr <Y> const & r); // never throws

Template <class Y> explicit shared_ptr (weak_ptr <Y> const & r );

Template <class Y> explicit shared_ptr (std: auto_ptr <Y> & r );
 

Shared_ptr & operator = (shared_ptr const & r); // never throws

Template <class Y> shared_ptr & operator = (shared_ptr <Y> const & r); // never throws

Template <class Y> shared_ptr & operator = (std: auto_ptr <Y> & r );
 

Void reset (); // never throws

Template <class Y> void reset (Y * p );

Template <class Y, class D> void reset (Y * p, D d );
 

T & operator * () const; // never throws

T * operator-> () const; // never throws

T * get () const; // never throws
 

Bool unique () const; // never throws

Long use_count () const; // never throws
 

Operator unspecified-bool-type () const; // never throws
 

Void swap (shared_ptr & B); // never throws
};

Most member functions are similar to auto_ptr, but without release (see note), reset is used to discard the ownership of the object or change the ownership of the object, this will reduce the reference count of the original object.

 
Note:
 
The QA in the Boost document explains why the release function is not provided.
 

Q. Why doesn't shared_ptr provide a release () function?

A. shared_ptr cannot give away ownership unless it's unique () because the other copy will still destroy
The object.
Consider:
Shared_ptr <int> a (new int );

Shared_ptr <int> B (a); // a. use_count () = B. use_count () = 2
 
Int * p = a. release ();
 

// Who owns p now? B will still call delete on it in its destructor.
Furthermore, the pointer returned by release () wocould be difficult to deallocate reliably,
As the source shared_ptr cocould have been created with a custom deleter.

Use_count returns the number of reference counts. unique is used to check whether the ownership is exclusive (use_count is 1). swap is used to exchange two shared_ptr objects (that is, the objects owned by the exchange ), there is a bool type conversion operator that enables shared_ptr to be used in the desired bool type context. For example, we usually use if (pointer) to determine whether a pointer is null. There are many shared_ptr usage routines in the Boost library. The document also lists the usage of many shared_ptr instances. The most useful and commonly used one is to pass the Dynamic Allocation object and the reference counting mechanism, now we can safely wrap dynamically allocated objects in shared_ptr to span modules and pass through thread boundaries. Shared_ptr automatically manages the lifecycle of objects for us. Well, C ++ can also appreciate the advantages of using references in Java.

In addition, remember to use Objective C ++ (or other C ++ books). Scott Meyer tells you: in a system composed of multiple modules, A module does not need to try to release resources allocated by another module, but should follow the principle of who allocates and who releases resources. The correct principle is sometimes overlooked (too cumbersome), and resources are encapsulated in shared_ptr for transmission. shared_ptr ensures that resources are no longer owned, the delete statement of the module that generates the resource is called.

Shared_ptr can be copied and assigned values, and the copy behavior is equivalent and can be compared. This means that it can be put into the general container (vector, list) of the standard library) and associated container (map ). Shared_ptr can be used to hold multi-State objects, for example, the following example: class Base
{
}

Class Derived: public Base
{
}
 

Shared_ptr <Base> sp_base (new Derived );

Even shared_ptr has a multi-state Behavior: Derived * pd = new Derived;
 
Shared_ptr <Derived> sp_derived (pd );
Shared_ptr <Base> sp_base2 (sp_derived); The preceding statement is valid. shared_ptr completes the required type conversion. When the shared_ptr template parameter Base is indeed the Base class of Derived. The last is A small reminder, whether it is using auto_ptr or shared_ptr, never write such code: A * pa = new;
Xxx_ptr <A> ptr_a_1 (pa );
Xxx_ptr <A> ptr_a_2 (pa );

Obviously, pa will be deleted at the end of the lifecycle of ptr_a_1 and ptr_a_2, and pa will be deleted twice, which will definitely cause your program to crash. Of course, this misuse example is obvious, but in some cases, you may accidentally write the following code (well, I admit I did this ): void DoSomething (xxx_ptr <A>)
{

// Do something
}
 
Class
{
DoSomething ()
{

Xxx_ptr <A> ptr_a (this );
DoSomething (ptr_a );
}
};
 
Int main ()
{

A;
A. doSomething ();

// Continue do something with a, but it was already destory
}

In function. what happened in doSomething (), which had to wrap itself into a xxx_ptr to call DoSomething, but when the function was over, xxx ptr_a is destroyed, and the program crashes immediately or crashes at a certain point in time! Therefore, when using smart pointers as function parameters, be careful with such misuse. Sometimes using smart pointers as function parameters is not necessarily a concern. For example, follow the following suggestions, do not use xxx_ptr <A> as the parameter type of A function in A non-member function that is part of an interface of type A or A helper function that is closely related to.

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.