C++ 智能指针

A smart pointer is a class object that acts like a pointer but has addiction features. --《C++ Primer》第六版

一、使用普通指针的问题

1) 每次调用 remodel,动态分配内存,最后没有释放该资源,将导致memory leak.

1 void remodel(std::string& str)
2 {
3     std::string* ps = new std::string(str);//动态分配内存
4     ...
5     str = ps;
6     return;
7 }

2) 即使最后释放资源,但是在中间抛出异常,则delete 语句无法执行,仍导致memory leak.

 1 void remodel(std::string& str)
 2 {
 3     std::string* ps = new std::string(str);//动态分配内存
 4     ...
 5     if(weird_thing())//抛出异常
 6        throw_exception();
 7     str = *ps;
 8     delete ps;//释放动态分配的内存
 9     return;
10 }

 二、智能指针使用实例

主要有三种智能指针,auto_ptr/unique_ptr/shared_ptr。定义一个指向类A的智能指针pA:auto_ptr<A> pA(new A)。  

 1 #include <iostream>
 2 #include <string>
 3 #include <memory>
 4 using namespace std;
 5 class Report
 6 {
 7 public:
 8     Report(const string s):str(s){
 9         cout<<"Object created!
";
10     }
11     ~Report(){
12         cout<<"Object deleted!
";
13     }
14     void comment() const{
15         cout<<str<<"
";
16     }
17 private:
18     string str;
19 };
20 
21 int main()
22 {
23     {//auto_ptr
24         auto_ptr<Report> ps (new Report("using auto_ptr"));
25         ps->comment(); // use -> to invoke a member function
26     }
27     cout<<"
";
28     {//shared_ptr
29         shared_ptr<Report> ps (new Report("using shared_ptr"));
30         ps->comment();
31     }
32     cout<<"
";
33     {//unique_ptr
34         unique_ptr<Report> ps (new Report("using unique_ptr"));
35         ps->comment();
36     }
37     return 0;
38 }
View Code

结果:当指针生命周期结束时,会自动调用所指向对象的析构函数

 三、使用智能指针的注意

1) 普通指针和智能指针间需要通过显示转换

智能指针有显示构造函数,它的参数是指针。普通指针需要显示转换成智能指针:Each of these classes has an explicit constructor taking a pointer as an argument. Thus, there is no automatic type cast from a pointer to a smart pointer object. 

1 shared_ptr<double> pd;
2 double *p_reg = new double;
3 pd = p_reg; // not allowed (implicit conversion)
4 pd = shared_ptr<double>(p_reg); // allowed (explicit conversion
5 shared_ptr<double> pshared = p_reg; // not allowed (implicit conversion)
6 shared_ptr<double> pshared(p_reg); // allowed (explicit conversion)

 2) 智能指针不能非动态分配的对象作为构造函数的参数

因为它最后会用delete 操作来释放该资源。When pvac expires, the program would apply the delete operator to non-heap memory, which is wrong.

1 string vacation("I wandered lonely as a cloud.");
2 shared_ptr<string> pvac(&vacation); // NO!

四、为什么少使用auto_ptr?

1) auto_ptr and unique_ptr 策略

多个智能指针不能同时指向同一个对象。假设 A 指向 C, 当使用 B=A 赋值后,原来的智能指针A就失去了对C的所有权,即不能通过A来访问对象C。

Institute the concept of ownership, with only one smart pointer allowed to own a particular object. Only if the smart pointer owns the object will its destructor delete the object.Then have assignment transfer ownership.This is the strategy used for auto_ptr and for unique_ptr, although unique_ptr is somewhat more restrictive.

2) shared_ptr 策略

引用计数:每次赋值会使计数器递增;指针过期会使计数器递减;当最后一个指针过期(计数器为0)将调用 delete。

Create an even smarter pointer that keeps track of how many smart pointers refer to a particular object.This is called reference counting.Assignment, for example, would increase the count by one, and the expiration of a pointer would decrease the count by one. Only when the final pointer expires would delete be invoked.

3)auto_ptr 实例

多个auto_ptr指向同一个对象,会使原来的指针失效,非法访问

 1 #include <iostream>
 2 #include <string>
 3 #include <memory>
 4 using namespace std;
 5 
 6 int main()
 7 {
 8     //files:一个包含5个string 对象的数组
 9     auto_ptr<string> files[5] = 
10     {
11         auto_ptr<string> (new string("Fowl balls")),
12         auto_ptr<string> (new string("Duck Walks")),
13         auto_ptr<string> (new string("Chicken Runs")),
14         auto_ptr<string> (new string("Turkey Errors")),
15         auto_ptr<string> (new string("Goose Eggs"))
16     };
17 
18     auto_ptr<string> pwin;
19     pwin = files[2]; //files[2] 失去对象的ownership
20     cout << "The nominees for best avian baseball film are
";
21     for (int i = 0; i < 5; i++)
22         cout<<*files[i]<<endl;
23     cout<<"The winner is "<<*pwin<<"!
";
24     return 0;
25 }
View Code

4) unique_ptr

当多个unique_ptr指向同一个对象,会产生编译错误

1 unique_ptr< string> pu1(new string "Hi ho!");
2 unique_ptr< string> pu2;
3 pu2 = pu1; //#1 not allowed
4 unique_ptr<string> pu3;
5 pu3 = unique_ptr<string>(new string "Yo!"); //#2 allowed

unique_ptr可以使用new[](delete[])。The auto_ptr template uses delete, not delete [], so it can only be used with new, not with new []. But unique_ptr has a new[], delete[] version: std::unique_ptr< double[]>pda(new double(5)); // will use delete []

 五、如何选择智能指针

1) shared_ptr

程序里需要用多个指针指向同一个对象。比如:拥有一个数组指针,且需要标识出一些特别的元素(最大/最小);有两个对象都需要指向第三个类的对象;使用STL容器,容器的对象为指针。

2) unique_ptr

程序里不需要多个指针指向同一个对象。比如:把unique_ptr 作为函数的返回值,它指向一块动态分配的内存。

unique_ptr<int> make_int(int n){
    return unique_ptr<int>(new int(n));
}
原文地址:https://www.cnblogs.com/coolqiyu/p/5590317.html