Smart pointers for C + +

Source: Internet
Author: User

Guide

has been to the smart pointer has a mysterious bright, although usually not how to use the smart pointer, also looked at the STL in one of the smart pointer auto_ptr, but has always been curious about the design of smart pointer So, today read the "C + + Primer Plus" in the introduction of smart pointers, here also summarized.

Directory
    1. The design idea behind the smart pointer
    2. Simple Introduction to C + + smart pointers
    3. Why Abandon Auto_ptr?
    4. Why is unique_ptr better than auto_ptr?
    5. How do I select a smart pointer?
Body 1. The design idea behind the smart pointer

First, let's look at the difference between a normal object and a pointer:

Why do local variable objects not manually release resources, and pointers need to manually dispose of resources?

Because the objects of a class are all destructors, local variables automatically call their destructors after they leave a valid interval, so there is no need to manually free up memory. But the pointer is not the same, the pointer has two layers of things, the first layer is the pointer itself, he can also release their own occupied memory, the second layer is the pointer to the memory block, this memory block is required to use Delete/free manual release.

  

From this, we can think of, in fact, the smart pointer is not a real pointer, it is not really mysterious, it is a pointer to the object.

This is the design idea behind the smart pointers of Auto_ptr, Unique_ptr and shared_ptr.

I would like to summarize briefly:

    Encapsulate the basic type pointer as a pointer to a class object (this class is definitely a template to accommodate the needs of different basic types) and write a DELETE statement in the destructor to delete the memory space pointed to by the pointer.

2. Simple Introduction to C + + smart pointers

STL provides us with four smart pointers: Auto_ptr, Unique_ptr, shared_ptr and weak_ptr (not discussed in this article).
Template auto_ptr is a solution provided by c++98, C+11 has been abandoned and offers two other solutions. However, although Auto_ptr was abandoned, it has been used for many years: at the same time, if your compiler does not support the other two resolution forces, AUTO_PTR will be the only option.

  Use note points

  • All smart pointer classes have a explicit constructor, with pointers as arguments. For example, Auto_ptr's class template prototype is:
  • templet<class t>class  auto_ptr {  explicit0);   ...};

    Therefore, you cannot automatically convert a pointer to a smart pointer object, which must be explicitly called:

  • shared_ptr<Double>PD;Double*p_reg =New Double;PD= P_reg;//Not allowed (implicit conversion)PD = shared_ptr<Double> (P_reg);//allowed (explicit conversion)shared_ptr<Double> pshared = p_reg;//Not allowed (implicit conversion)shared_ptr<Double> pshared (P_reg);//allowed (explicit conversion)

  • One thing to avoid for all three smart pointers:
  • string Vacation ("I wandered lonely as a cloud. " ); shared_ptr<string> PVAc (&vacation);   // No

    When PVAc expires, the program will use the delete operator for non-heap memory, which is an error.

3. Why abandon auto_ptr?

First look at the following assignment statement:

string> PS (newstring ("I reigned lonely as a cloud.") ); auto_ptr<string>= PS;

What do the above assignment statements do?

If PS and vocation are regular pointers, two pointers will point to the same string object. This is unacceptable because the program will attempt to delete the same object two times-one time when PS expires and the other is when vocation expires.

There are several ways to avoid this problem:

    • define the discovered computers value operator so that it performs a deep copy. this way, two pointers will point to different objects, one of which is a copy of the other, and the disadvantage is a waste of space, so the smart pointers do not take this scenario.
    • establish the concept of ownership (ownership). only one smart pointer can be owned for a particular object, so that only the constructor that owns the smart pointer to the object will delete the object. Then let the assignment action transfer ownership. This is the strategy for auto_ptr and Uniqiie_ptr , but Unique_ptr's strategy is stricter.
    • creates a smart, higher pointer that tracks the number of smart pointers that reference a particular object. This is called a reference count. For example, when assigning a value, the count will be added 1, and when the pointer expires, the count will be reduced by 1. Delete is called when it is reduced to 0 o'clock. This is the strategy adopted by shared_ptr .

Of course, the same strategy applies to copy constructors as well. Every method has its uses, but why is it that it has to abandon auto_ptr?
Here is an example to illustrate.

#include <iostream>#include<string>#include<memory>using namespacestd;intMain () {auto_ptr<string> films[5] ={auto_ptr<string> (New string("Fowl Balls")), Auto_ptr<string> (New string("Duck walks")), Auto_ptr<string> (New string("Chicken Runs")), Auto_ptr<string> (New string("Turkey Errors")), Auto_ptr<string> (New string("Goose Eggs")) }; Auto_ptr<string>Pwin; Pwin= films[2];//Films[2] loses ownership. Transfer ownership from films[2] to Pwin, at which time films[2] no longer references the string and becomes a null pointercout<<"The nominees for best avian baseballl film are\n";  for(inti =0; I <5; ++i) cout<< *films[i] <<Endl; cout<<"The winner is"<< *pwin <<Endl, cin.Get(); return 0;}

Running under the Discovery program crashes, the reason in the above comment has been said very clearly,films[2] is already a null pointer , the following output access null pointer of course it will crash. But if you replace auto_ptr with shared_ptr or UNIQUE_PTR, the program will not crash for the following reasons:

    • It works fine when using shared_ptr because shared_ptr uses reference counting , Pwin and films[2] all point to the same piece of memory, and when the space is freed, there is no error in deleting an object more than once because the size of the reference count value is determined beforehand.
    • Compile error when using unique_ptr, like Auto_ptr, Unique_ptr also takes ownership model , but when using UNIQUE_PTR, the program does not wait for the run phase to crash, and the compiler has an error because of the following line of code:
    • unique_ptr<string>= films[2//  films[2] loses ownership.

Guide you to discover potential memory errors.

This is why you want to abandon auto_ptr, one sentence is summed up: avoid potential memory crashes.

4. Why is unique_ptr better than auto_ptr?

It may be thought that the previous example has shown why UNIQUE_PTR is better than auto_ptr, which is a security issue, and the following is a clear point. Take a look at the following statement:

auto_ptr<string> P1 (newstring ("auto"//  #1auto_ptr<string> p2;                       // #2p2 = p1;                                   // #3

In the statement # #, P2 takes over ownership of the string object, and the ownership of the P1 is stripped. As I said earlier, this is a good thing to prevent P1 and P2 destructors from trying to delete the same object;

But if the program then tries to use P1, it would be a bad thing, because P1 no longer points to valid data.

unique_ptr<string> P3 (newstring ("auto");   // #4unique_ptr<string> P4;                       //#5p4 = p3;                                      // #6

The compiler considers the statement to be illegal, avoiding the problem that P3 no longer points to valid data. Therefore,Unique_ptr is more secure than auto_ptr .

But there's a smarter place for unique_ptr.


Sometimes a smart pointer is assigned to another hanging pointer that does not leave a danger. The following function definitions are assumed:

  

unique_ptr<String> Demo (constChar * s) {    unique_ptr<string > Temp (newstring  (s));     return  temp;}

And suppose you write the following code:

unique_ptr<string>= Demo ('uniquely special ');

The demo () returns a temporary UNIQUE_PTR, and then PS takes over all the objects that were originally returned to the unique_ptr, and the temporary unique_ptr is destroyed when it returns, that is, there is no chance to use UNIQUE_PTR to access the invalid data, in other words, This assignment does not cause any problems, that is, there is no reason to prohibit such assignment.

In fact, the compiler does allow this assignment, which is where unique_ptr is smarter.

In summary, when the program attempts to assign a unique_ptr to another, if the source unique_ptr is a temporary rvalue, the compiler allows this, and if the source unique_ptr will exist for some time, the compiler will disallow this, such as:

unique_ptr<string> pu1 (New string("Hello World")); Unique_ptr<string>PU2;PU2= PU1;//#1 not allowedunique_ptr<string>PU3;PU3= unique_ptr<string> (New string(" You"));//#2 allowed

One of the # # leaves hangs of the unique_ptr (PU1), which can cause harm.

and # # does not leave the dangling unique_ptr because it calls the Unique_ptr constructor, which creates a temporary object that is destroyed after its ownership is given to PU3. This behavior, as the case may be, suggests that unique_ptr is better than allowing two auto_ptr to be assigned.

Of course, you might really want to do something like # #, which is unsafe only when you use a discarded smart pointer in a non-intelligent way, such as when you dereference it.

To safely reuse this pointer, you can assign a new value to it. C + + has a standard library function, Std::move (), that allows you to assign one unique_ptr to another.

Here is an example of using the demo () function, which returns a Unique_ptr<string> object:
With move, the original pointer still transfers ownership into a null pointer, which can be re-assigned.

unique_ptr<string>= Demo ("hello"== Demo ( " Alexia "  << *ps2 << *ps1 << Endl;

5. How do I select a smart pointer?

After mastering these smart pointers, you might think of another question: which smart pointers should be used in real-world applications?
Here are a few guidelines to use.

(1) If the program wants to use multiple pointers to the same object, select Shared_ptr. Such situations include the following:

    • There is an array of pointers, and some auxiliary pointers are used to indicate specific elements, such as the largest element and the smallest element;
    • Two objects contain a pointer to the third object;
    • The STL container contains pointers. Many STL algorithms support replication and assignment operations that can be used for shared_ptr, but not for unique_ptr (compiler emit warning) and auto_ptr (behavior uncertainty). If your compiler does not provide shared_ptr, you can use the shared_ptr provided by the Boost library.

(2) If the program does not require multiple pointers to the same object, you can use Unique_ptr.

If the function uses new to allocate memory and returns a pointer to that memory, declaring its return type as UNIQUE_PTR is a good choice. In this way, all rights are transferred to the unique_ptr that accept the return value, and the smart pointer is responsible for calling delete. Unique_ptr can be stored in the STL container at that, as long as it is not called to copy or assign one unique_ptr to another algorithm (such as sort ()).

  

unique_ptr<int> Make_int (intN) {    returnunique_ptr<int> (New int(n));}voidShow (unique_ptr<int> &p1) {cout<< *a <<' ';}intMain () {... vector<unique_ptr<int> >VP (size);  for(inti =0; I < vp.size (); i++) Vp[i]= Make_int (rand ()% +);//Copy Temporary unique_ptrVp.push_back (Make_int (rand)% +));//OK because arg is temporaryFor_each (Vp.begin (), Vp.end (), show);//Use for_each ()    ...}

  

Where the push_back call is not a problem because it returns a temporary unique_ptr, the unique_ptr is assigned to a unique_ptr in the VP.

Also, if you pass an object by value instead of by reference to show (), For_each () will be illegal because this will cause the pi to be initialized with a non-temporary unique_ptr from the VP, which is not allowed.

As mentioned earlier, the compiler will find an attempt to use unique_ptr incorrectly.

When Unique_ptr is the right value, it can be assigned to shared_ptr, which is the same as assigning a unique_ptr to a condition that needs to be met. As before, in the following code, the return type of Make_int () is unique_ptr<int>:

unique_ptr<int));   // OKshared_ptr<int> spp (PUP);                       // Not allowed, pup as Lvalueshared_ptr<int));   // OK

The template shared_ptr contains an explicit constructor that you can use to convert the Rvalue unique_ptr to shared_ptr. SHARED_PTR will take over all the objects originally owned by Unique_ptr.

Auto_ptr can also be used when conditions are met for unique_ptr requirements, but unique_ptr is a better choice. If your compiler does not have unique_ptr, consider using the scoped_ptr provided by the Boost library, which is similar to unique_ptr.

Smart pointers for C + +

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.