Summary of C ++ shared_ptr and shared_ptr

Source: Internet
Author: User

Summary of C ++ shared_ptr and shared_ptr

Share_ptr is also a smart pointer. Similar to auto_ptr learning. Therefore, we recommend that you first learn auto_ptr and then shared_ptr. The first two in this blog are the summaries of auto_ptr. Hope you can check it out.

 

The biggest difference between Shared_ptr and auto_ptr is that shared_ptr solves the problem of sharing object ownership between pointers, that is, the strange issue of assigning values in auto_ptr. Therefore, it meets the container requirements and can be used in containers. Auto_ptr obviously prohibits the ownership of shared objects and cannot be used in containers.

       int * a=new int(2);       shared_ptr<int> sp1(a);       shared_ptr<int> sp2(sp1);     OK

Of course, shared_ptr, as a smart pointer, has some similar properties as shared_ptr. They are essentially classes, but they use pointers. These are all solutions to prevent memory leakage. All are implemented using RAII technology.

 

Note: When shared_ptr is used, the header file # include <memory> must also be referenced.

 

Because the source code of shared_ptr is too complex, we do not provide the source code. Similar to auto_ptr learning.

 

1. First, the shared_ptr class has two member variables. T * px and unsign long * pn;

T * px; it is obviously the same as auto_ptr, used to store object pointers.

Pn records how many shared_ptr objects have the same object. Pn is shared among shared_ptr objects, similar to static member variables.

template<class T>class shared_ptr{private:       T *px; // contained pointer    unsignedlong* pn; // reference counter}

Summary: in fact, the principle of shared_ptr is to use px to record pointers, and use * pn to record the number of owner vertex _ptr of the object pointed to by px. When a shared_ptr object reaches the scope, resources are not released. Only when * pn becomes 0 will the Resources pointed to by the pointer be released.

 

2. A simple source code (It is still important to understand the source code.)

# Pragma once // simple implementation version of shared_ptr // a reference-based smart pointer // It works perfectly with the stl container with namespace boost {template <class T> class shared_ptr {typedef unsigned longsize_type; private: T * px; // contained pointer size_type * pn; // reference counterpublic: // constructor ------------------------------------------------- 2/* int * a = new int (2 ); shared_ptr <int> sp; shared_ptr <int> sp (a); */explicitshared_ptr (T * p = 0): px (p) {pn = new size_type (1 );} /* Derived d; shared_ptr <Base> ap (d); */template <typename Y> shared_ptr (Y * py) {pn = newsize_type (1); px = py ;} // copy constructor ----------------------------------------------/* int * a = new int; shared_ptr <int> sp (a); shared_ptr <int> sp1 (sp ); */shared_ptr (constshared_ptr & r) throw (): px (r. px) {++ * r. pn; pn = r. pn;}/* shared_ptr <Derived> sp1 (derived); shared_ptr <Base> sp2 (sp1); */template <typename Y> shared_ptr (constshared _ Ptr <Y> & r) // used for Polymorphism {px = r. px; ++ * r. pn; pn = r. pn; // shared_count: op = doesn't throw} // overload value assignment operator = ------------------------------------------------ shared_ptr & operator = (const shared_ptr & r) throw () {if (this = & r) return * this; dispose (); px = r. px; ++ * r. pn; pn = r. pn; return * this;} template <typename Y> shared_ptr & operator = (const shared_ptr <Y> & r) // used for Polymorphism {dispose (); px = r. px; ++ * r. pn; pn = r. pn; // shared_count: op = Doesn't throwreturn * this ;}~ Shared_ptr () {dispose ();} void reset (T * p = 0) {if (px = p) return; if (-- * pn = 0) {delete (px);} else {// allocate newreference // counter // fix: prevent leak if new throwstry {pn = new size_type;} catch (...) {// undo effect of-* pn above to // meet effects guarantee ++ * pn; delete (p); throw ;} // catch} // allocate newreference counter * pn = 1; px = p;} // resetreference operator * () const throw () {return * Px;} pointer operator-> () const throw () {return px;} pointer get () constthrow () {returnpx;} size_type use_count () constthrow () // {return * pn;} bool unique () const throw () // {return * pn = 1;} private: void dispose () throw () {if (-- * pn = 0) {delete px; delete pn ;}}; // shared_ptrtemplate <typename, typenameB> inline bool operator = (shared_ptr <A> const & l, shared_ptr <B> const & r) {return l. get () = R. get ();} template <typename A, typenameB> inline bool operator! = (Shared_ptr <A> const & l, shared_ptr <B> const & r) {return l. get ()! = R. get () ;}// namespace boost


Note:

 

3. Shared_ptr and auto_ptr both have similar rules:

Let's take a look at their copy construction and Heavy Load assignment. We can see that:

Not Allowed

       int* a=new int(2);       shared_ptr<int>sp=a;//  error       sp=a;//    error

A pure pointer is not allowed to assign values to a smart pointer or create a copy. Only smart pointers can be assigned values or copied to another smart pointer.

Int * a = new int (2); shared_ptr <int> sp (a); // constructor shared_ptr <int> sp1 (sp); // copy to construct sp1 = sp; // assign a value

The same is true in auto_ptr.

 

4. Pay attention to several shared_ptr functions.

Ø Reset () function: resets the function.

The standard is:

Int * a = new int (2); int * B = new int (3); shared_ptr <int> sp2 (a); shared_ptr <int> sp1 (); shared_ptr <int> sp (a); sp. reset (B); sp. reset (); sp. reset (sp2 );-----!!! Yes.

To allow sp to gain B's ownership. Lose a's ownership. Note that this will reduce the owner of a. 1. When the owner of a changes to 0, resources of a will be released.

Ø Swap () function: Exchange Function

       int* a=new int(2);       shared_ptr<int> sp(a);       shared_ptr<int> sp1(a);       sp.swap(sp1);

The px and pn values in the two shared_ptr are exchanged.

Ø Get () function: returns px

Ø Use_count function: returns * pn, which is the number of object owners.

Ø Unique function: * pn = 1; change the number of object owners to 1. Return bool

* And->

 

5. tr1 contains several symbols related to shared_ptr:

Template <classT, class U>

Booloperator = (shared_ptr <T> const & a, shared_ptr <U> const & B );

Determine whether the owner object is the same

 

Template <classT, class U>

Bool operator! = (Shared_ptr <T> const & a, shared_ptr <U> const & B );

Determine whether the owner object is different

 

Template <classT, class U>

Bool operator <(shared_ptr <T> const & a, shared_ptr <U> const & B );

It is very useful in the LIST of STL.

       int* a=new int(2);       int* b=new int(3);       shared_ptr<int> sp(a);       shared_ptr<int> sp1(b);       if(sp<sp1)              cout<<"2222"<<endl;

6. Note that the public dispose function does not exist in the shared_ptr in the real world. This function is only used to avoid code duplication.

 

7. Note that the destructor in shared_ptr does not directly release resources, but calls the dispose function. If * pn = 0, the resources will be released.

 

8. Security of multi-thread shared_ptr

Shared_ptr itself is not 100% thread-safe. Its reference count is safe and lockless, but the object read/write is not,BecauseShared_ptr has two data members. read/write operations cannot be atomic.. According to the document, the thread security level of shared_ptr is the same as that of the built-in type, standard library container, and string, that is:

  • A shared_ptr entity can be read by multiple threads at the same time;
  • Two shared_ptr entities can be written by two threads at the same time, and the "destructor" is a write operation;
  • If you want to read and write the same shared_ptr object from multiple threads, You need to lock the object.

 

I found two very interesting things:

1. Check the source code in tr1 and find two such things:

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

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

What is D in it? The source code is interpreted as "d" as a deleter ). So far, we suddenly found that we could specify a deleteer for shared_ptr. When * pn = 0, we did not release resources, but called our own deleteer for it.

 

When shared_ptr references 0, mongo_ptr calls the release function to release resources.

When we want to reference 0 times, shared_ptr will use D instead of releasing resources but calling the operation we specified;

void foo(int * d){       cout<<"1234"<<endl;} int _tmain(int argc, _TCHAR* argv[]){       int* a=new int(2);       shared_ptr<int> sp(a,foo);       shared_ptr<int> sp1(sp);       sp.reset();       sp1.reset();       //_CrtDumpMemoryLeaks();       system("pause");       return 0;}


Note! :

1. the parameter of the specified deleteer must be int *; it corresponds to the int in shared_ptr <int>. It cannot be anything else, or it is also wrong to be empty. Because the system will assign the shared_ptr object px to the parameters of the delete tool, we can also release resources in the delete tool.

2. Only the number of references of a is 0. Therefore, if sp1.reset () is not available (). And does not call the foo function.

 

2. When using shared_ptr, be careful and think about the internal meaning of the operation.

1>

       int* a=new int(2);       shared_ptr<int> sp(a);       shared_ptr<int> sp1(sp);       sp.reset();//--------(1)       sp.reset();//--------(2)


Here (1) indicates that the sp is reset. Note (2) There is no function and the number of references of a cannot be changed to 0. think about the reset function. (2) when the object pn in sp is empty, the * pn value cannot be changed.

 

2>

     int* a=new int(2);       shared_ptr<int> sp(a);//----------(1)       shared_ptr<int> sp1(a);//---------(2)

Note: Here (2) is also incorrect. Think about the shared_ptr constructor. (1), sp px points to a and * pn is 1. in (2), px points to a, and * pn is also 1. this is obviously a problem. A is referenced twice, but * pn is 1. When the final scope reaches, the memory is released twice, which causes an exception.

 

Summary: differences between shared_ptr and auto_ptr.

Shared_ptr has two variables: one record object address and one record reference count.

Auto_ptr has only one variable to record the object address.

 

Shared_ptr can have one resource with multiple shared_ptr instances.

Auto_ptr can have only one resource for one auto_ptr.

 

Shared_ptr can be used to assign values so that the two addresses direct to the same resource.

The assignment of Auto_ptr is strange. The source loses the resource ownership and the target obtains the resource ownership.

 

When Shared_ptr reaches the scope, resources may not be released.

When Auto_ptr is reached, resources will be released.

 

Shared_ptr has multi-thread security issues, but auto_ptr does not.

 

Shared_ptr can be used in containers, while auto_ptr cannot be used in containers.


Shared_ptr allows you to specify the deleteer when constructing and reset functions. But auto_ptr cannot.

 

Also, if you use a smart pointer (whether shared_ptr or auto_ptr), you must clear the internal implementation principles of the source code. In addition, you must think about the internal implementation principles of the function before using it. Be careful.



Vs2008 for shared_ptr of C ++

Shared_ptr must be self-contained only after VS2008 SP1. the header file is # include <memory>, or the boost Library (boost: shared_ptr) and the header file is # include <boost/shared_ptr.hpp>.

Vs2008 error C2039: "shared_ptr": Not a member of "std: tr1"

Std: tr1: shared_ptr,
An error was reported during compilation: error C2039: "shared_ptr": Not a member of "std: tr1.
Cause: vs2008 SP1 is not installed.
VS90sp1-KB945140-CHS.exe:
Www.microsoft.com/...58056E
VS2008SP1CHSX1512981. iso:
Www.microsoft.com/..b5ce61
If vs2008 SP1 is not installed, use Boost: shared_ptr.

How to: create and use shared_ptr instances

Make_shared is exceptionally secure. It uses the memory control block allocated by the same call and the resource to reduce the construction overhead. If make_shared is not used, you must create an object using an explicit new expression and pass it to the shared_ptr constructor. The following example demonstrates how to declare and initialize shared_ptr together with the new object. VBC # C ++ F # JScriptPowerShell No code example is currently available or this language may not be supported. the following example demonstrates how to declare and initialize a shared_ptr instance that has been assigned by another shared_ptr with the object share ownership. Assume that sp2 is the initialized shared_ptr. VBC # C ++ F # JScriptPowerShell No code example is currently available or this language may not be supported. shared_ptr is also used in standard template library (STL) containers when you use the "Copy element algorithm. Elements that can be packaged in shared_ptr can be copied to other basic container memory that is fully understood, as long as they are not needed and no longer used. The following example demonstrates how to use the replace_copy_if algorithm in the shared_ptr instance in the vector. VBC # C ++ F # JScriptPowerShell No code example is currently available or this language may not be supported. You can use dynamic_pointer_cast, static_pointer_cast, and const_pointer_cast to convert shared_ptr. These functions are similar to the dynamic_cast, static_cast, and const_cast operators. The following example demonstrates how to test the derivation type of each element in the shared_ptr vector of the base class, then copy the elements and display information about them. VBC # C ++ F # JScriptPowerShell No code example is currently available or this language may not be supported. You can use shared_ptr to another function in the following way: Use shared_ptr value. This call of the copy constructor will increase the reference count and make the caller owner. There is a small amount of system overhead for this operation, and it may be meaningful to pass through the shared_ptr object based on experience. With this option, when the Code Protocol (prompt or explicit) requires that the called party be the owner between the caller and the called party. Use shared_ptr reference or constant reference. In this case, the reference count does not increase. Therefore, the called party can access the pointer as long as the caller does not exceed the range. Alternatively, the caller can decide to create a shared_ptr based on the reference to form a shared owner. This option is used when the caller is not aware of the called party, or if the caller must use shared_ptr and avoid replication operations for performance reasons. Base Object through base pointer or reference. This allows the caller to use objects, but does not share ownership or extend the lifetime. If the caller creates the shared_ptr of the original pointer, the new shared_ptr is independent of the original shared_ptr and does not control such basic resources. With this option, the list of agreements between the caller and the called party indicates that the caller retains the ownership of the shared_ptr lifetime at a scheduled time. When you decide how to use shared_ptr to determine whether the called party must share the ownership of such basic resources. "Owner" is acceptable... the remaining full text>

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.