c/c++ 智能指針 shared_ptr 使用

来源:https://www.cnblogs.com/xiaoshiwang/archive/2018/09/27/9711169.html
-Advertisement-
Play Games

智能指針 shared_ptr 使用 上一篇 "智能指針是啥玩意" ,介紹了什麼是智能指針。 這一篇簡單說說如何使用智能指針。 一,智能指針分3類:今天只嘮嘮shared_ptr shared_ptr unique_ptr weak_ptr 二,下表是shared_ptr和unique_ptr都支持 ...


智能指針 shared_ptr 使用

上一篇智能指針是啥玩意,介紹了什麼是智能指針。

這一篇簡單說說如何使用智能指針。

一,智能指針分3類:今天只嘮嘮shared_ptr

  • shared_ptr
  • unique_ptr
  • weak_ptr

二,下表是shared_ptr和unique_ptr都支持的操作

操作 功能描述
shared_ptr<T> sp 空智能指針,可以指向類型為T的對象
unique_ptr<T> up 空智能指針,可以指向類型為T的對象
p 將p用作一個條件判斷,如果p指向一個對象,則為true
*p 解引用p,獲得它指向的對象
p->mem 等價於(*p).mem,訪問p所指對象的mem成員
p.get() 返回p中保存的指針。如果指向的對象已經被釋放,就是一個危險的指針
swap(p, q)或者p.swap(q) 交換p和q中的指針

上面操作的驗證代碼

#include <memory>
#include <iostream>
#include <vector>

using namespace std;

class Test{
public:
  Test(int d = 0):data(d){cout << "cr:" << data << endl;}
  ~Test(){cout << "fr:" << data << endl;}
  void fun(){
    cout << "Test func(" << data << ")" << endl;
  }
private:
  int data;
};
int main(){
  //shared_ptr<Test> sp = make_shared<Test>();                                  
  Test* pt = new Test();
  shared_ptr<Test> sp(pt);
  if(sp){
    cout << "sp指向了對象" << endl;
  }
  (*sp).fun();
  shared_ptr<int> isp;
  if(!isp){
    cout << "isp沒有指向對象" << endl;
  }
  Test* tmp1 = sp.get();
  auto sp1 = make_shared<Test>(10);
  Test* tmp2 = sp1.get();
  swap(sp, sp1);
  tmp1->fun();//0
  tmp2->fun();//10
  //sp和sp1所指向的對象被交換了
  sp.get()->fun();//10
  sp1.get()->fun();//0

}

三,下表是shared_ptr獨有的操作

操作 功能描述
make_shared<T>(args) 返回shared_ptr,指向一個動態分配的類型為T的對象。使用args初始化此對象。
shared_ptr p是q的拷貝;遞增q中的計數器。q中的指針必須能轉化成T*。
p = q p和q都是shared_ptr,所保存的指針必須能相互轉換。遞減p的引用計數;遞增q的引用計數;如果p的引用計數變為0,則釋放p管理的對象的記憶體。
p.unique() 如果p.use_count()為1,則返回true;否則返回false
p.use_count() 返回與p共用對象的智能指針的數量;性能很低,用於調試。

上面操作的驗證代碼

  shared_ptr<Test> tsp = make_shared<Test>(11);
  cout << tsp.use_count() << endl;//1                                           
  //tsp1和tsp指向相同的對象,這個對象的計數器加1                                
  shared_ptr<Test> tsp1(tsp);
  cout << tsp.use_count() << endl;//2                                           
  //用tsp1改變了對象的data的值,所以用tsp再訪問這個對象,發現對象被改變了        
  tsp1->setData(111);
  tsp->fun();//111                                                              

  shared_ptr<Test> q(new Test(20));
  cout << q.use_count() << endl;//1                                             
  cout << tsp.use_count() << endl;//2                                           
  //如果q不是智能指針,q指向的Test(20)這塊記憶體就泄露了                           
  //q是智能指針,所以自動釋放了Test(20)這塊記憶體                                 
  q = tsp;
  cout << q.use_count() << endl;//3                                             
  cout << tsp.use_count() << endl;//3                                           
  if(!q.unique()){
    cout << "不是只有一個智能指針指向了某個對象" << endl;
  }

四,智能指針作為函數的返回值

shared_ptr<Test> hun(int d){
  return make_shared<Test>(d);
}
void use_hun1(int d){
  shared_ptr<Test> p = hun(d);
  p->fun();
}//p離開作用域後,它指向的記憶體會被自動釋放                                      
shared_ptr<Test> use_hun2(int d){
  shared_ptr<Test> p = hun(d);//計數器為1                                       
  return p;//返回p時,計數器遞增,為2                                           
}//離開作用域後,計數器遞減,為1,因為不為0,所以不會釋放

一到四的小例子:

include <memory>
#include <iostream>
#include <vector>

using namespace std;

class Test{
public:
  Test(int d = 0):data(d){cout << "cr:" << data << endl;}
  ~Test(){cout << "fr:" << data << endl;}
  void fun(){
    cout << "Test func(" << data << ")" << endl;
  }
  void setData(int d){
    data = d;
  }
private:
  int data;
};

//test3 智能指針作為函數的返回值                                                
shared_ptr<Test> hun(int d){
  return make_shared<Test>(d);
}
void use_hun1(int d){
  shared_ptr<Test> p = hun(d);
  p->fun();
}//p離開作用域後,它指向的記憶體會被自動釋放                                      
shared_ptr<Test> use_hun2(int d){
  shared_ptr<Test> p = hun(d);//計數器為1                                       
  return p;//返回p時,計數器遞增,為2                                           
}//離開作用域後,計數器遞減,為1,因為不為0,所以不會釋放                       
int main(){
  //test1 shared_ptr和unique_ptr都支持的操作                                    
  /*                                                                            
  //shared_ptr<Test> sp = make_shared<Test>();                                  
  Test* pt = new Test();                                                        
  shared_ptr<Test> sp(pt);                                                      
  if(sp){                                                                       
    cout << "sp指向了對象" << endl;                                             
  }                                                                             
  (*sp).fun();                                                                  
  shared_ptr<int> isp;                                                          
  if(!isp){                                                                     
    cout << "isp沒有指向對象" << endl;                                          
  }                                                                             
  Test* tmp1 = sp.get();                                                        
  auto sp1 = make_shared<Test>(10);                                             
  Test* tmp2 = sp1.get();                                                       
  swap(sp, sp1);                                                                
  tmp1->fun();                                                                  
  tmp2->fun();                                                                  
  sp.get()->fun();                                                              
  sp1.get()->fun();                                                             
  */

  //test2 shared_ptr獨有的操作                                                   
  /*                                                                            
  shared_ptr<Test> tsp = make_shared<Test>(11);                                 
  cout << tsp.use_count() << endl;//1                                           
  //tsp1和tsp指向相同的對象,這個對象的計數器加1                                
  shared_ptr<Test> tsp1(tsp);                                                   
  cout << tsp.use_count() << endl;//2                                           
  //用tsp1改變了對象的data的值,所以用tsp再訪問這個對象,發現對象被改變了        
  tsp1->setData(111);                                                           
  tsp->fun();//111                                                              
                                                                                
  shared_ptr<Test> q(new Test(20));                                             
  cout << q.use_count() << endl;//1                                             
  cout << tsp.use_count() << endl;//2                                           
  //如果q不是智能指針,q指向的Test(20)這塊記憶體就泄露了                           
  //q是智能指針,所以自動釋放了Test(20)這塊記憶體                                 
  q = tsp;                                                                      
  cout << q.use_count() << endl;//3                                             
  cout << tsp.use_count() << endl;//3                                           
  if(!q.unique()){                                                              
    cout << "不是只有一個智能指針指向了某個對象" << endl;                       
  }                                                                             
  */

  //test3 智能指針作為函數的返回值                                              
  /*                                                                            
  auto ap = use_hun2(22);                                                       
  ap->fun();                                                                    
  use_hun1(33);                                                                 
  */

}

github完整代碼

五,智能指針的註意事項

把shared_ptr放入容器中時,之後不再需要全部元素,只使用其中一部分的話,要用erase刪除那些不再需要使用的shared_ptr。如果不erase那些不再需要使用的shared_ptr,shared_ptr就不會釋放它指向的記憶體。

六,智能指針的小例子,讓多個對象共用相同的狀態。

  • 有個類shared_vector,裡面有個shared_ptr,指向了一個vector,類shared_vector的對象a2拷貝a1時,實現a1和a2共用vector。
  • 類un_shared_vector沒有使用shared_ptr,所以沒有共用vector。
include <iostream>
#include <memory>
#include <vector>
#include <string>

using namespace std;

class shared_vector{
public:
  typedef vector<string>::size_type size_type;
  shared_vector():data(make_shared<vector<string>>()){}
  shared_vector(initializer_list<string> il):
    data(make_shared<vector<string>>(il)){}
  size_type size()const{return data->size();}
  bool empty()const{return data->empty();}
  //尾部插入,刪除元素                                                          
  void push_back(const string& s){data->push_back(s);}
  void pop_back(){data->pop_back();}
  //訪問元素                                                                    
  string& front(){return data->front();}
  string& back(){return data->back();}

private:
  shared_ptr<vector<string>> data;
};

class un_shared_vector{
public:
  typedef vector<string>::size_type size_type;
  un_shared_vector():data(vector<string>()){}
  un_shared_vector(initializer_list<string> il):data(il){}
  size_type size()const{return data.size();}
  bool empty()const{return data.empty();}
  //尾部插入,刪除元素                                                          
  void push_back(const string& s){data.push_back(s);}
  void pop_back(){data.pop_back();}
  //訪問元素                                                                    
  string& front(){return data.front();}
  string& back(){return data.back();}

private:
  vector<string> data;
};

int main(){
  shared_vector sv{"aa","bb"};
  shared_vector sv1(sv);
  //因為sv和sv1共用同一個vector,                                               
  //所以通過sv改變vector後,通過sv1也發現了相同的改變
  sv.push_back("cc");
  cout << sv1.back() << endl;

  un_shared_vector usv{"11","22"};
  un_shared_vector usv1(usv);
  //因為usv和usv1不共用同一個vector,                                           
  //所以通過usv改變vector後,usv1裡面的vector沒有跟著變化
  usv.push_back("33");
  cout << usv1.back() << endl;
  cout << usv.back() << endl;
}

github完整代碼

c/c++ 學習互助QQ群:877684253

本人微信:xiaoshitou5854


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

-Advertisement-
Play Games
更多相關文章
  • 最近寫了一個限流的插件,所以避免不了的接觸到了一些限流演算法。本篇文章就來分析一下這幾種常見的限流演算法 分析之前 計數器演算法 這個演算法可以說是限流演算法中最簡單的一種演算法了。 計數器演算法的意思呢就是當介面在一個時間單位中被訪問時,我就記下來訪問次數,直到它訪問的次數到達上限。 當一個請求過來時,我們就會 ...
  • 今年有人提出了2018年微服務將瘋狂至死,可見微服務的爭論從未停止過。在這我將自己對微服務的理解整理了一下,希望對大家有所幫助。 1.什麼是微服務 1)一組小的服務(大小沒有特別的標準,只要同一團隊的工程師理解服務的標識一致即可) 2)獨立的進程(java的tomcat,nodejs等) 3)輕量級 ...
  • 本文長度為2042字,建議閱讀6分鐘。所有「」包裹的文字,只對第一次出現進行高亮顯示。 閱讀目錄 「高可用」的作用? 如何來衡量「高可用」 做「高可用」的本質 結語 「高可用」的作用? 如何來衡量「高可用」 做「高可用」的本質 結語 「高可用」的作用? 如何來衡量「高可用」 做「高可用」的本質 結語 ...
  • 一.準備工作 準備3台機器,這樣才能完成分散式集群的實驗,當然能有更多機器更好: 192.168.3.64(e1) 192.168.3.62 (e2) 192.168.3.63(e3) 角色劃分: 3台機器全部安裝jdk1.8,因為elasticsearch是java開發的 3台全部安裝elasti ...
  • 教程:一:字典的創建 1:字典的介紹 >d = {key1:value1, key2:values2} (1)dictionary(字典) 是 Python 中最有用的數據類型。字典是無序的對象集合 (2)字典當中的元素是通過鍵來存取的,而不是通過偏移存取。 (3)字典是一種映射類型,它是一個無序的 ...
  • 美國時間 09 月 25 日,Oralce 正式發佈了 Java 11,這是據 Java 8 以後支持的首個長期版本。 為什麼說是長期版本,看下麵的官方發佈的支持路線圖表。 可以看出 Java 8 擴展支持到 2025 年,而 Java 11 擴展支持到 2026 年。 現在大部分都在用 Java ...
  • 程式員應該將核心關註點放在業務上,而不應該將時間過多的浪費在CRUD中,多數的ORM框架都把增加、修改與刪除做得非常不錯了,然後資料庫中查詢無疑是使用頻次最高、複雜度大、與性能密切相關的操作,我們希望得到一種使用方便,查詢靈活的ORM框架,MyBatis可以滿足這些要求,MyBatis是一個支持普通 ...
  • Java當中的泛型 01 這就存在一個問題,如果集合存儲元素時,而且存儲對象有很多,而且對象類型不相同,就很容易導致隱患。 在 中該文件 在編譯的時候不會出現錯誤是因為該存儲的是 的任何類型的對象,所以不會出現錯誤,編譯通過了。編譯後為 到運行。 如果要解決問題,可以把問題提前到編譯的時候去解決,讓 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...