程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> c++ auto_ptr智能指針,auto_ptr智能指針

c++ auto_ptr智能指針,auto_ptr智能指針

編輯:C++入門知識

c++ auto_ptr智能指針,auto_ptr智能指針


c++ auto_ptr智能指針


該類型在頭文件memory中,在程序的開通通過 #include<memory> 導入,接下來講解該智能指針的作用和使用。

使用方法:

  auto_ptr<type> ptr(new type());   這是該指針的定義形式,其中 type 是指針指向的類型,ptr 是該指針的名稱。

  比如該type 是int,具體定義如下:

  auto_ptr<int> ptr(new int(4));

  比如該type 是map<int,vector<int> >,具體定義如下:

  auto_ptr<map<int,vector<int> > > ptr(new map<int,vector<int> > ());

  當然可以先定義,後賦值,如下所示:

  auto_ptr<map<int,int> > ptr;

  ptr = auto_ptr<map<int,int> >(new map<int,int> ());

 

作用1:保證一個對象在某個時間只能被一個該種類型的智能指針所指向,就是通常所說的對象所有權。

 

作用2:對指向的對象自動釋放的作用,詳情看如下代碼。

代碼片段一:

 

#include <iostream>

#include <string.h>
#include <memory>
#include <string>
#include <Windows.h>
#include <map>

#include <ctime>
#include <vector>
using namespace std;#define MAXN 20000000

class test_ptr
{
public:
    map<int,int> *p;
    test_ptr()
    {
        p = new map<int,int>();
        for(int i = 0;i<MAXN;i++)
            p->insert(make_pair(i,i));
    }
};

int main(int argc,char *argv[])
{
    for(int i = 0;i<100;i++)
    {
        Sleep(1000);
        cout << i << endl;  // 輸出 創建次數
        test_ptr * tmp = new test_ptr();

    }
    
    system("pause");
    return 0;
}

 

在某些情況下,可能我們就會寫出上面的代碼來,通過運行會發現存在內存溢出。對於一些經驗老道的程序員可能會作如下改寫:

代碼片段二:

#include <iostream>

#include <string.h>
#include <memory>
#include <string>
#include <Windows.h>
#include <map>
#include <ctime>
#include <vector>

using namespace std;


#define MAXN 20000000

class test_ptr
{
public:
    map<int,int> *p;
    test_ptr()
    {
        //p  = auto_ptr<map<int,int> > (new map<int,int>());
        p = new map<int,int>();
        for(int i = 0;i<MAXN;i++)
            p->insert(make_pair(i,i));
    }
    
    ~test_ptr()
    {
        delete p;
    }
    
};

int main(int argc,char *argv[])
{
    for(int i = 0;i<100;i++)
    {
        Sleep(1000);
        cout << i << endl;   
        test_ptr * tmp = new test_ptr();

    }
    
    system("pause");
    return 0;
}

在test_ptr 類中的析構函數中添加內存釋放代碼,但是在main函數中,定義的局部指針,當局部指針失效時並不會自動調用析構函數,在這種情況下也會導致內存洩漏問題。當然,如果細心的程序員可以在 test_ptr * tmp = new test_ptr() 後面加上一句 delete tmp ,這樣也能夠釋放內存,不會出現內存洩漏問題。但是在某些情況下,很容易漏寫,為了解決此問題,auto_ptr 就能發揮作用了。

代碼片段三:

#include <iostream>

#include <string.h>
#include <memory>
#include <string>
#include <Windows.h>
#include <map>
#include <ctime>
#include <vector>

using namespace std;


#define MAXN 20000000

class test_ptr
{
public:
    map<int,int> *p;
    test_ptr()
    {
        p = new map<int,int>();
        for(int i = 0;i<MAXN;i++)
            p->insert(make_pair(i,i));
    }
    
    ~test_ptr()
    {
        delete p;
    }
    
};

int main(int argc,char *argv[])
{
    for(int i = 0;i<100;i++)
    {
        Sleep(1000);
        cout << i << endl;    //輸出創建次數
        auto_ptr<test_ptr> tmp = auto_ptr<test_ptr> (new test_ptr());
        
    }
    
    system("pause");
    return 0;
}

在main函數中,創建test_ptr類型指針時,該指針是auto_ptr 類型的智能指針,當智能指針失效時,會自動調用該類的析構函數。所以這種寫法可以不再顯示調用delete 語句了。但是該智能指針也只是保證調用類的析構函數,如果析構函數並沒有釋放類中聲明的變量,那該怎麼辦。

代碼片段四:

#include <iostream>

#include <string.h>
#include <memory>
#include <string>
#include <Windows.h>
#include <map>
#include <ctime>
#include <vector>

using namespace std;


#define MAXN 20000000

class test_ptr
{
public:
    //auto_ptr<map<int,int> > p;
    map<int,int> *p;
    test_ptr()
    {
        //p  = auto_ptr<map<int,int> > (new map<int,int>());
        p = new map<int,int>();
        for(int i = 0;i<MAXN;i++)
            p->insert(make_pair(i,i));
    }
    /*
    ~test_ptr()
    {
        delete p;
    }
    */
};

int main(int argc,char *argv[])
{
    for(int i = 0;i<100;i++)
    {
        Sleep(1000);
        cout << i << endl;    //輸出創建次數
        auto_ptr<test_ptr> tmp = auto_ptr<test_ptr> (new test_ptr());
        
    }
    
    system("pause");
    return 0;
}

在這種情況下,還是會出現內存洩漏問題,為了解決該問題,對類中聲明的指針也是需要聲明為auto_ptr類型。

代碼片段五:

#include <iostream>

#include <string.h>
#include <memory>
#include <string>
#include <Windows.h>
#include <map>
#include <ctime>
#include <vector>

using namespace std;


#define MAXN 20000000

class test_ptr
{
public:
    auto_ptr<map<int,int> > p;
    test_ptr()
    {
        p  = auto_ptr<map<int,int> > (new map<int,int>());
        for(int i = 0;i<MAXN;i++)
            p->insert(make_pair(i,i));
    }
  
};

int main(int argc,char *argv[])
{
    for(int i = 0;i<100;i++)
    {
        Sleep(1000);
        cout << i << endl;    //輸出創建次數
        auto_ptr<test_ptr> tmp = auto_ptr<test_ptr> (new test_ptr());
     
    }
    
    system("pause");
    return 0;
}

這樣就不用顯示定義類的析構函數,不用在外部顯示調用delete函數,當然如果盡早調用delete函數也是可以的,盡早釋放內存也比該指針失效再釋放好一些,這些就是為了防止忘記調用。

 

通過如上分析:可以得出如下結論。

1 定義了智能指針,當智能指針失效時會自動調用類的析構函數。

2 在 類中定義的智能指針,不必在析構函數中顯示的delete,當外部調用該類的析構函數時,會自動釋放該智能指針指向的對象,釋放內存。

3 如果類中定義的是智能指針,但是外部沒有觸發類中的析構函數調用,該智能指針指向的對象還是不能釋放。

 

auto_ptr  智能指針的bug

auto_ptr 智能指針在c++ 11 標准中已經被拋棄,被拋棄的原因就是因為該bug。前面也提到過,一個對象只能被一個智能指針所引用,這樣就會導致一個賦值問題。看如下代碼

代碼片段六:

 1 #include <iostream>
 2 
 3 #include <string.h>
 4 #include <memory>
 5 #include <set>
 6 
 7 using namespace std;
 8 
 9 
10 #define MAXN 20000000
11 
12 void pri(auto_ptr<set<int> > p)
13 {
14     set<int>::iterator ite = p->begin();
15     for(;ite!=p->end();ite++)
16     {
17         cout << *ite << endl;
18     }
19 }
20 
21 int main(int argc,char *argv[])
22 {
23     auto_ptr<set<int> > ptr(new set<int> ());
24 
25     for(int i = 0;i< 3;i++)
26     {
27         int a;
28         cin >> a;
29         ptr->insert(a);
30     }
31 
32     pri(ptr);
33 
34     pri(ptr);
35     
36     system("pause");
37     return 0;
38 }

初看這代碼沒什麼問題,不過運行程序會崩潰。這就是該智能指針最大的bug, 在程序32行 調用pri(ptr) ,程序到這並沒什麼問題,但是第二次調用pri(ptr) 時程序就會崩潰。原因就是前面講過,一個對象智能被一個智能指針所指向,在第一次調用pri()函數時,為了保證這一原則,當把ptr指針傳入pri函數時,程序內部就把ptr置為空,所以到第二次調用時,就會出現崩潰的情況。對於這種情況的解決之道就是使用shared_ptr 指針(該指針的原理是通過引用計數器來實現的)。

如果要使用shared_ptr 智能指針,需要安裝boost庫,該庫還包括許多其他功能。有興趣的可以嘗試以下,該類中的智能指針還是比較好用。也不存在很多其他bug。

有時間再詳細介紹boost庫中shared_ptr指針

 

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved