c++ auto_ptr智能指針

来源:http://www.cnblogs.com/ChenAlong/archive/2016/07/12/5662851.html
-Advertisement-
Play Games

c++ auto_ptr智能指針 該類型在頭文件memory中,在程式的開通通過 #include<memory> 導入,接下來講解該智能指針的作用和使用。 使用方法: auto_ptr<type> ptr(new type()); 這是該指針的定義形式,其中 type 是指針指向的類型,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指針

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、邂逅XML 文件種類是豐富多彩的,XML作為眾多文件類型的一種,經常被用於數據存儲和傳輸。所以XML在現今應用程式中是非常流行的。本文主要講Java解析和生成XML。用於不同平臺、不同設備間的數據共用通信。 XML文件的表現:以“.xml”為文件擴展名的文件; 存儲結構:樹形結構; 節點名稱區分 ...
  • ...
  • UML關係:繼承(泛化)、實現、依賴、關聯、聚合、組合的聯繫與區別 ...
  • 描述 風景迷人的小城Y市,擁有n個美麗的景點。由於慕名而來的游客越來越多,Y市特意安排了一輛觀光公交車,為游客提供更便捷的交通服務。觀光公交車在第0分鐘出現在1號景點,隨後依次前往2、3、4……n號景點。從第i號景點開到第i+1號景點需要Di分鐘。任意時刻,公交車只能往前開,或在景點處等待。 設共有 ...
  • 1.打開pip的文檔官網 https://pip.pypa.io/en/stable/ ,進入installation。在installation里,我們需要的是get-pip.py這個腳本。 選中後下載,我把它另存到C盤。 2.打開cmd命令行,打開C盤根目錄並運行get-pip.py腳本。當然, ...
  • 游戲服務端架構 介紹 端游、手游服務端常用的架構是什麼樣的? http://www.zhihu.com/question/29779732 根據知乎問答文章整理而成。 作者:韋易笑 謝邀,手游頁游和端游的服務端本質上沒區別,區別的是游戲類型。 類型1:卡牌、跑酷等弱交互服務端 卡牌跑酷類因為交互弱,... ...
  • JNA 調用 dll 庫時,保錯: 我環境是 64 位 win7. java.lang.UnsatisfiedLinkError: %1 不是有效的 Win32 應用程式。 解決方法, 刪掉了系統中的 64 位的 JDK,就沒有再報該錯誤了。 ...
  • Java.util.zip 提供用於讀寫標準 ZIP 和 GZIP 文件格式的類。 還包括使用 DEFLATE 壓縮演算法(用於 ZIP 和 GZIP 文件格式)對數據進行壓縮和解壓縮的類。 依賴 Jdk 編寫該工具類,不依賴任何第三方 jar,隨用隨取,實現功能大體如下: 1.目錄級別遞歸壓縮與解壓 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...