"C + + Primer Plus" 16.2 Smart pointer template class

Source: Internet
Author: User
Tags rand throw exception

A smart pointer is a class object that behaves like a pointer, and there are other functions for this object alone. This section describes three smart pointer classes that can help you manage dynamic memory allocations. Let's take a look at what features are needed and how they are implemented. Take a look at the following function:
void Remodel (std::string & str)
{
std::string * PS = new std::string (str);
...
str = PS;
Return
}
You may have found defects in them. Whenever called, the function allocates memory in the heap, which is never recycled, causing a memory leak. Your brother also knows the solution-just don't forget to add the following statement before the return statement to release the allocated memory:
Delete PS;
However, it is seldom the best to deal with the "don't forget" approach. Because sometimes you may forget, sometimes you may remember, but you may inadvertently fall in the depths or the code dropped. Even if you do not forget, there may be problems. Take a look at the following variants:
void Remodel (std::string & str)
{
std::string * PS = new std::string (str);
...
if (weird_thing ())
Throw exception ();
str = *PS;
Delete PS;
Return
}
When an exception occurs, delete is not executed, and therefore a memory leak is also caused.
This problem can be fixed in the manner described in chapter 14th, if there is a more dexterous solution. See what you need here. When a function such as remodel () terminates (whether it is terminated normally or terminated due to an exception), the local variable is removed from the stack memory-so the memory occupied by the pointer PS is freed. If the memory that the PS points to is also released, then how good. If PS has a destructor, the destructor frees the memory it points to when PS expires. So the problem with PS is that it indicates a regular pointer, not a class object with destructors. If it is an object, you can have its destructor delete the pointed memory when the object expires. This formal auto_ptr, unique_ptr and shared_ptr behind the thought. Template auto_ptr is a solution provided by c++98, C++11 has abandoned it and provides two additional workarounds. However, although auto_ptr is discarded, it has been used for many years, and if your compiler does not support the other two workarounds,
Auto_ptr will be the only option.

16.2.1 Use only pointers
These three pointer-only templates (Auto_ptr/unique_ptr and shared_ptr) define pointers-like objects, and you can assign new (direct or indirect) addresses to this pair of images. When only the pointer expires, its destructor uses Delete to free memory. Therefore, if you assign the address returned by new to these pairs, you do not have to remember to release the memory later: when only the pointer expires, the memory is automatically freed.
To create only pointer objects, you must include the header file memory, which is defined by the file template. Then use the usual template syntax to instantiate a pointer of the desired type. For example, the template auto_ptr contains the following structure constructors:
Template<class X> class Auto_ptr {
Public
Explicit Auto_ptr (x* p = 0) throw ();
...};
throw () means that the constructor does not throw an exception and, like Auto_ptr, throw () is discarded. Therefore, a auto_ptr that requests an X type will get a auto_ptr that points to the X type:
Auto_ptr<double> PD (new double); PD an auto_ptr to double
(use with place of double * PD)
Auto_ptr<string> PS (new string); PS a auto_ptr to string
(use in place of String * PS)
The new double is a pointer to the newly allocated memory block. It is the argument of the constructor auto_ptr<double>, which corresponds to the argument p in the prototype. Similarly, the new string is also an argument to the constructor. The other two types can only use the same syntax as pointers:
Unique_ptr<double> PDU (new double); PDU an unique_ptr to double
Shared_ptr<string> PSS (new string); PSS a shared_ptr to string
Therefore, to convert the remodel () function, proceed as follows in 3 steps:
1. Contains the head file memory;
2. Replace the pointer to string with a pointer-only object that points to string;
3. Remove the DELETE statement.
The following is the result of modifying the function using Auto_ptr:
#include <memory>
void Remodel (std::string & str)
{
Std::auto_ptr<std::string> PS (new std::string (str));
...
if (weird_thing ())
Throw exception ();
str = *PS;
Delete PS; NO Longer NEEDED
Return
}
Notice that only the pointer template is in the namespace Std. The program listing 16.5 is a simple program that demonstrates how to use all three pointers only. To compile the program, your compiler must support c++11 new classes Share_ptr and Unique_ptr. Each pointer can be placed within a block of code so that the pointer expires when it leaves the code block. The report class uses methods for reporting object creation and destruction.
Program Listing 16.5 smrtptrs.cpp
--------------------------------------------------
Smrtptrs.cpp--using three kinds of smart pointers
Requires support of c++11 shared_ptr and Unique_ptr
#include <iostream>
#include <string>
#include <memory>

Class Report
{
Private
std::string str;
Public
Report (const std::string s): Str (s)
{std::cout << "Object created!\n";}
~report () {std::cout << "Object deleted!\n";}
void Comment () const {std::cout << str << "\ n";}
};

int main ()
{
{
Std::auto_ptr<report> PS (new report ("Using auto_ptr"));
Ps->comment (); Use, to invoke a member function
}
{
Std::shared_ptr<report> PS (new report ("Using shared_ptr"));
Ps->comment ();
}
{
Std::unique_ptr<report> PS (new report ("Using Unique_ptr"));
Ps->comment ();
}
return 0;
}
--------------------------------------------------
(Note: My g++ version does not have shared_ptr and unique_ptr)

Why 16.2.3 unique_ptr better than auto_ptr
Take a look at the following statement:
auto_ptr<string> P1 (New string ("Auto")); #1
auto_ptr<string> P2; #2
P2 = 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, it is good time to prevent P1 and P2 destructors from trying to get the same object, but if the program subsequently tries to use P1, it would be a bad thing because P1 no longer points to valid data.
Let's look at the use of unique_ptr:
Unique_ptr<string> P3 (New string ("Quto")); #4
Unique_ptr<string> P4; #5
P4 = 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 (a compile-time error is more secure than a potential program crash).
Sometimes, however, one pointer can be assigned to another hanging pointer that does not leave a danger. The following function definitions are assumed:
Unique_ptr<string> Demo (const char * s)
{
Unique_ptr<string> Temp (new string (s));
return TRMP;
}
And suppose you write the following code:
Unique_ptr<string> PS;
PS = 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 returned Unique_ptr is destroyed. This is fine, because PS has ownership of the string object. But another advantage here is that the temporary Unique_ptr returned by the demo () is soon destroyed, and there is no chance to use it to access invalid data. In other words, there is no reason to prohibit such assignments. Amazingly, the compiler does allow this assignment!
In summary, when the program attempts to assign one unique_ptr to another, the compiler allows this if the source unique_ptr is a temporary rvalue, and if the source unique_ptr will exist for some time, the compiler will disallow this:
using namespace Std;
Unique_ptr<string> pu1 (New string "Ho ho!");
Unique_ptr<string> pu2;
PU2 = PU1; #1 not allowed
Unique_ptr<string> Pu3;
PU3 = unique_ptr<string> (new string "yo!"); #2 allowed
The statement # # will leave the Unique_ptr (PU1), which can cause harm. The statement # # # does not leave dangling unique_ptr because it calls the constructor of Unique_ptr, which can be destroyed when its ownership is transferred to the PU. This behavior, which varies with the situation, indicates that the UNIQUE_PTR is superior to the auto_ptr that allow two assignments. It is also forbidden (just a suggestion that the compiler does not prohibit) to use auto_ptr in the container object, allowing the unique_ptr to be used alone. If the container algorithm attempts to perform an operation similar to statement # # to a container containing unique_ptr, it will cause a compilation error, and there will be no problem if the algorithm tries to perform an operation similar to statement # # #. For Auto_ptr, an operation similar to statement # # # could lead to an indeterminate behavior and a breakdown of the nerves.
Of course, your brother is doing something like statement # #. This type of replication is not secure only if only pointers, such as dereferencing, are used together in a way that can be revoked. To safely reuse this value frame, 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:
using namespace Std;
Unique_ptr<string> PS1, PS2;
PS1 = Demo ("Uniquely Special");
PS2 = Move (PS1); Enable Assignment
PS1 = Demo ("and more");
cout << *ps2 << *ps2 << Endl;
How can unique_ptr distinguish between safe and unsafe usage? The answer is that it uses C++11 's new move constructor and Rvalue reference, which Zhejiang discussed in the 18th chapter.
There is another bit more than the auto_ptr,unique_ptr. It has a variant that can be used for arrays. Remember that you must pair the delete and new with the Delete [] and new [] pairs. The template auto_ptr uses delete instead of delete [], so it can only be used with new. and cannot be used with new []. Single unique_ptr have versions that use new [] and delete []:
Std::unique_ptr<double []> PDA (new double (5)); would use delete []
Note: When using new to allocate memory, you cannot use auto_ptr and shared_ptr when allocating memory using new []. When you do not allocate memory using new, you cannot use auto_ptr or shared_ptr; Unique_ptr is not used when allocating memory without using new or new [].

16.2.4 Selecting Smart Pointers
What kind of pointers should be used? If your program uses multiple pointers to the same object, you should select shared_ptr. Such situations include having an array of pointers and using some auxiliary pointers to identify specific elements, such as the largest element and the smallest element; Come on, that brother Caprice contains a pointer to a 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.
If your 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, ownership is transferred to the UNIQUE_PTR that accepts the return value, and the only pointer will be responsible for calling delete. You can store unique_ptr in an STL container as long as you do not call a method or algorithm (such as sort ()) that assigns or assigns one unique_ptr to another. For example, you can use code snippets similar to the following in your program, assuming the program contains the correct include and using statements:
unique_ptr<int> make_int (int n)
{
return unique_ptr<int> (new int (n));
}
void Show (Unique_ptr<int> & PI)//pass by reference
{
cout << *a << ";
}
int main ()
{
vector<unique_ptr<int> > VP (Size);
for (int i = 0; i < vp.size (); i++)
Vp[i] = Make_int (rand ()% 1000); Copy temporary Unique_ptr
Vp.push_back (Male_int (rand ()% 1000)); OK because ARG is temporary
For_each (Vp.begin (), Vp.end (), show); Use For_each ()
...
}
There is no problem with the push_back () call, because it returns a temporary unique_ptr that Unique_ptr is assigned to a unique_ptr in the VP. In addition, if you pass an object by value instead of by reference to show (), the For_each () syntax 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. In front of the state, 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 one unique_ptr to another that needs to be met. As before, in the following code, the return type of Make_int () is unique_ptr<int&gt:
Unique_ptr<int> Pup (Make_int (rand ()% 1000)); Ok
Shared_ptr<int> spp (PUP); Not allowed, pups an lvalue
Shared_ptr<int> SPR (Make_int (rand ()% 1000)); 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 provide unique_ptr, consider using the scoped_ptr provided by the Boost library, which is similar to unique_ptr.



"C + + Primer Plus" 16.2 Smart pointer template class

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.