c/c++ 智能指針 shared_ptr 和 new結合使用

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

智能指針 shared_ptr 和 new結合使用 用make_shared函數初始化shared_ptr是最推薦的,但有的時候還是需要用new關鍵字來初始化shared_ptr。 一,先來個表格,嘮嘮new和shared_ptr | 操作 | 功能描述 | | | | | shared_ptr\ ...


智能指針 shared_ptr 和 new結合使用

用make_shared函數初始化shared_ptr是最推薦的,但有的時候還是需要用new關鍵字來初始化shared_ptr。

一,先來個表格,嘮嘮new和shared_ptr

操作 功能描述
shared_ptr<T> p(q) 智能指針p管理內置指針q所指向的對象;q必須指向new分配的記憶體,且能夠轉換為T*。
shared_ptr<T> p(u) p從unique_ptr u那裡接管了原來u所指向對象的所有權,並將u置為空。
shared_ptr<T> p(q, d) p接管了內置指針q所指的對象的所有權。q必須能轉換為T*。p將使用可調用對象d來代替delete。
p.reset() 如果p是唯一指向其對象的shared_ptr,reset會釋放此對象。如果沒傳參數q,將p置為空。
p.reset(q) 如果傳遞了內置指針q,會讓p指向q所指向的對象,否則會將p置為空。
p.reset(q, d) 如果還傳遞了參數d,將會調用d,而不是delete來釋放q

二,智能指針和普通指針一起使用的陷阱

void pro(shared_ptr<int> ptr){

}  
shared_ptr<int> p(new int(42));//計數器為1                                    
pro(p);//p作為參數會進行copy遞增它的計數器,在pro內部計數器是2                
int i = *p;//計數器為1                                                        
cout <<  i << endl;

int* bad =  new int(11);
//pro(bad);//編譯錯誤                                                         
pro(shared_ptr<int>(bad));//合法,但出了pro,bad所指向的記憶體會被釋放          
int j = *bad;//解指針bad就會產生難以預料的結果   

三,也不要使用get初始化另一個智能指針或為智能指針賦值

  shared_ptr<int> p(new int(12)); 
  int* q = p.get();
  { 
    shared_ptr<int> tmp(q); 
  }//程式塊結束後,q所指向的對象被釋放
  int f = *p;//解指針p就會產生難以預料的結果
  cout << f << endl;

四,智能指針和異常

void f(){
    shared_ptr<int> sp(new int(11));
    //假設拋出了異常,而且在f中未捕獲
}//函數結束後shared_ptr自動釋放記憶體
void f1(){
    int* ip = new int(12);
    //假設delete語句前拋出了異常,而且在f中未捕獲
    delete ip;
}//函數結束後ip所指向的記憶體沒有被釋放。

五,智能指針使用的最佳建議

  • 不使用相同的內置指針初始化(或reset)多個智能指針。
  • 不使用get()初始化或reset另一個智能指針。
  • 不delete get()返回的指針。
  • 如果使用了get()返回的指針,請牢記,當最後一個對應的智能指針被銷毀後,你的指針就變為無效了。
  • 如果使用智能指針管理的資源不是new分配的記憶體,請傳遞給它一個刪除器。

小例子:

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

using namespace std;

class Test{
public:
  Test(int d = 0) : data(d){cout << "new:" << data << endl;}
  ~Test(){cout << "del:" << data << endl;}
private:
  int data;
};
void my_deleter(Test* t){
  cout << "my_deleter is work" << endl;
}
void pro(shared_ptr<int> ptr){

}
int main(){
  //test1 reset                                                                 
  /*                                                                            
  Test* tp = new Test(1);                                                       
  shared_ptr<Test> stp(tp);                                                     
  shared_ptr<Test> stp1(stp);                                                   
  stp.reset();                                                                  
  cout << stp << endl;                                                          
  */

  //test2 自定義刪除器                                                          
  /*                                                                            
  Test* tp = new Test(1);                                                       
  //不會調用Test的析構函數了,只調用my_deleter函數                              
  shared_ptr<Test> stp(tp, my_deleter);                                         
  shared_ptr<Test> stp1(stp);                                                   
  cout << stp.use_count() << endl;                                              
  Test* tp1 = new Test(2);                                                      
  stp1.reset(tp1, my_deleter);                                                  
  */

  //test3 不要混用普通指針和智能指針                                            
  /*                                                                            
  shared_ptr<int> p(new int(42));//計數器為1                                    
  pro(p);//p作為參數會進行copy遞增它的計數器,在pro內部計數器是2                
  int i = *p;//計數器為1                                                        
  cout <<  i << endl;                                                           
                                                                                
  int* bad =  new int(11);                                                      
  //pro(bad);//編譯錯誤                                                         
  pro(shared_ptr<int>(bad));//合法,但出了pro,bad所指向的記憶體會被釋放          
  int j = *bad;//解指針bad就會產生難以預料的結果                                
  */

  //test4 get的錯誤使用                                                         
  /*                                                                            
  shared_ptr<int> p(new int(12));                                               
  int* q = p.get();                                                             
  {                                                                             
    shared_ptr<int> tmp(q);                                                     
  }//程式塊結束後,q所指向的對象被釋放                                          
  int f = *p;//解指針p就會產生難以預料的結果                                    
  cout << f << endl;                                                            
  */
}

github完整代碼

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

本人微信:xiaoshitou5854


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

-Advertisement-
Play Games
更多相關文章
  • 教程:高能:語句結構都是由關鍵字開頭,用冒號結束! 一:語句結構for <variable> in <sequence>: <statements>else: # else可有可無 <statements>二:基本規則 (1)使用縮進來劃分語句塊,相同縮進數的語句在一起組成一個語句塊。 (2)seq ...
  • ![](https://img2018.cnblogs.com/blog/711958/201809/711958-20180928091826555-1354813331.jpg) ...
  • ![](https://img2018.cnblogs.com/blog/711958/201809/711958-20180928091434379-573436458.jpg) ...
  • 原文出自: "http://cmsblogs.com" import 標簽解析完畢了,再看 Spring 中最複雜也是最重要的標簽 bean 標簽的解析過程。 在方法 中,如果遇到標簽 為 bean 則調用 方法進行 bean 標簽解析,如下: 整個過程分為四個步驟 1. 調用 進行元素解析,解析過 ...
  • 前言 此系列是針對springboot的啟動,旨在於和大家一起來看看springboot啟動的過程中到底做了一些什麼事。如果大家對springboot的源碼有所研究,可以挑些自己感興趣或者對自己有幫助的看;但是如果大家沒有研究過springboot的源碼,不知道springboot在啟動過程中做了些 ...
  • 前言 為了攔截大部分請求,秒殺案例前端引入了驗證碼。淘寶上很多人吐槽,等輸入完秒殺活動結束了,對,結束了...... 當然了,驗證碼的真正作用是,有效攔截刷單操作,讓羊毛黨空手而歸。 驗證碼 那麼到底什麼是驗證碼呢?驗證碼作為一種人機識別手段,其終極目的,就是區分正常人和機器的操作。我們常見的互聯網 ...
  • Integer內部組成解析,常用方法簡介以及使用註意事項說明 ...
  • "題目鏈接" rmq求LCA,interesting。 一直沒有學這玩意兒是因為CTSC的Day1T2,當時我打的樹剖LCA 65分,gxb打的rmq LCA 45分。。。 不過rmq理論複雜度還是小一點的,就學一下把。 RMQ求LCA 我們要用到三個數組 $dfn[i]$:第$i$個節點位置的時間 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...