【語法】C++的內存管理 模板

內存管理:

在C語言中,動態開辟空間可以用malloc,calloc,realloc這三個函數,下面先來復習一下這三者的區別

malloc和calloc都是用來開辟新空間,calloc在malloc的基礎上還會初始化該空間為0,用法也不同

? ?malloc(sizeof(int)*n)? ? ? ?calloc(sizeof(int),n)? ?

realloc時用來給已經動態開辟好的空間擴容的具體用法示例如下

int* newp = (int*)realloc(p,sizeof(int)*n)

C語言內存管理方式在C++中可以繼續使用,但有些地方就無能為力而且使用起來比較麻煩,因此C++又提出了自己的內存管理方式:通過newdelete操作符進行動態內存管理。

void Test()
{// 動態申請一個int類型的空間int* ptr4 = new int;// 動態申請一個int類型的空間并初始化為10int* ptr5 = new int(10);// 動態申請10個int類型的空間int* ptr6 = new int[3];delete ptr4;delete ptr5;delete[] ptr6;
}

可以發現new和我們之前用的函數都有點不一樣,這是因為它是操作符 ,所以導致了它獨特的使用方法。

要特別注意new int(10)不是申請10個int空間,而是申請一個int空間并初始化為10,new int[10]才是申請10個int空間,但申請數組就不能初始化了

那new和malloc有什么區別呢?

在回答這個問題之前,我們先來看另外一組操作符

operator new和operator delete

盡管他們有operator,但這和類的那些重載函數不一樣,,operator new 和operator delete是系統提供的全局函數,用法和malloc相似

void Test()
{// 動態申請一個int類型的空間int* ptr4 = (int*)operator new(sizeof(int));// 動態申請10個int類型的空間int* ptr6 = (int*)operator new(sizeof(int)*3);operator delete(ptr4);operator delete[](ptr6);
}

下面是operator new的底層實現

/*
operator new:該函數實際通過malloc來申請空間,當malloc申請空間成功時直接返回;申請空間失敗,
嘗試執行空間不足應對措施,如果改應對措施用戶設置了,則繼續申請,否則拋異常。
*/
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{// try to allocate size bytesvoid *p;while ((p = malloc(size)) == 0)if (_callnewh(size) == 0){// report no memory// 如果申請內存失敗了,這里會拋出bad_alloc 類型異常static const std::bad_alloc nomem;_RAISE(nomem);}return (p);
}

通過該函數的實現可以得知,operator new也是調用的malloc,只不過在這基礎上如果開辟失敗會拋異常

operator delete 和free沒區別,因為釋放空間失敗直接終止進程,operator delete只是為了和operator new成對出現

除此之外,operator new和operator delete也是可以重載的,如果你想在開辟空間的基礎上做別的事情,就可以重載operator new/delete

new,operator new,malloc

上面將了operator new和malloc的區別,是在調用malloc的基礎上可以拋異常。

而new和operator new的區別則是在operator new的基礎上會調用自定義類型的構造函數,這是因為new 的原理就是

1.調用operator new函數申請空間?

2.在申請的空間上執行構造函數

?delete也相似

1.在空間上執行析構函數

2. 調用operator delete函數釋放空間?

?那既然new是在operator new的基礎上調用構造函數,有沒有什么辦法可以直接在operator new 的基礎上自己去調用構造函數呢?

有的兄弟,有的,這個時候就需要請出定位new

當我們已經通過malloc或operator new申請了空間后,如果想要調用該類的構造函數

Date *p = (Date*)operator new(sizeof(Date));
new(p) Date;

new后面的括號里面是指針名稱,后面跟類的名稱

正常來說是不能顯式調用構造函數的,構造函數都是在實例化類時隱式調用的,而定位new就算是一種顯式調用

總結:

new和malloc的區別

  1. ?new會調用構造函數,失敗拋異常,malloc失敗了返回0 ?
  2. ?malloc是一個函數,new是一個操作符
  3. malloc用法:參數傳字節數,返回值是void*;new后面跟申請對象的類型,返回值是類型的指針

malloc,operator new,new的關系

  1. malloc
  2. operator new -> malloc + 失敗拋異常
  3. new? ? ? ? ? ? ? ?-> operator new + 構造函數

讀者有沒有想過一個問題,為什么會有free,delete這樣的函數,有什么意義呢?

大家都知道free和delete都是用來釋放之前在中動態開辟的空間的,那如果不釋放有什么危害?

答案是會造成內存泄漏,雖說對小程序沒有什么危害,但對長期運行的程序,出現內存泄露危害很大,或者設備內存本身很小,也有危害,要防止可以用工具檢測或智能指針

?模板:

大家都知道,重載可以讓同一個函數名存在多個,根據參數的不同來選擇對應的函數,有些時候函數內部除了類型不同沒有任何的區別,這時用重載就會非常麻煩,就會用到模板(泛型編程)

模板分為函數模板和類模板

先來看下面一個Swap的函數模板

template<class T>//<typename T>也可以
void Swap( T& left, T& right)
{T temp = left;left = right;right = temp;
}

這是一個可以用于任何類型的Swap函數模板,其實就是在函數的上面一行寫上了template<class T>

之后不管調用Swap時是什么類型,都可以執行,但它執行的是這個函數模板嗎?

當然不是,函數模板是一個藍圖,它本身并不是函數,是編譯器用使用方式產生特定具體類型函數的模具。所以其實模板就是將本來應該我們做的重復的事情交給了編譯器。

也就是說模板本身并不會去執行,是在預處理階段生成對應的函數/類,真正去執行的是生成的函數/類

可以看到,三次調用的Swap的地址是不一樣的,所以是生成了三個不同參數的Swap,再分別調用

看上面這個代碼,可以看到模板的最后一行沒有加分號,但這并不影響編譯通過,這也證明了模板并不會參與編譯,只要沒有用到這個函數,預處理階段就不會生成相應的函數。

顯式實例化和隱式實例化

模板的實例化分為顯式和隱式,如Swap(a,b)就是隱式,?由編譯器自己去判斷應該調用什么類型的函數,也可以Swap<int>(a,b),這樣就是顯式實例化,指定編譯器必須要用int類型的函數。

如果a是int型,b是double型,Swap(a,b)也會報錯,因為不知道該生成那種函數,這時有兩種解決方法

  1. Swap(a,(int)b),這樣讓b也變成int類型,編譯器就知道該實例化生成一個int類型的Swap函數
  2. Swap<int>(a,b),直接顯式實例化也可以讓編譯器知道該實例化生成一個int類型的Swap函數

而類模板在實例化時必須顯式實例化,隱式實例化會報錯

并且函數模板和同名的函數可以共存

// 專門處理int的加法函數
int Add(int left, int right)
{return left + right;
}
// 通用加法函數
template <class T>
T Add(T left, T right)
{return left + right;
}
void Test()
{Add(1, 2);      // 與非模板函數匹配,編譯器不需要特化Add<int>(1, 2); // 調用編譯器特化的Add版本
}

有人可能會問,第一個Add會調用函數模板生成的函數還是另一個同名函數呢?

答案是同名函數。對于非模板函數和同名函數模板,如果其他條件都相同,在調動時會優先調用非模板函數而不會從該模板產生出一個實例。如果模板可以產生一個具有更好匹配的函數, 那么將選擇模板

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/895162.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/895162.shtml
英文地址,請注明出處:http://en.pswp.cn/news/895162.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

30~32.ppt

目錄 30.導游小姚-介紹首都北京? 題目? 解析 31.小張-旅游產品推廣文章 題目 解析 32.小李-水的知識? 題目? 解析 30.導游小姚-介紹首都北京? 題目 解析 新建幻燈片-從大綱-重置-檢查設計→主題對話框→瀏覽主題&#xff1a;考生文件夾&#xff08;注意&#x…

深度學習-交易預測

下面為你詳細介紹如何使用Python結合深度學習庫TensorFlow和Keras來構建一個簡單的交易預測模型。在這個示例中&#xff0c;我們以股票價格預測為例&#xff0c;假設我們要根據過去一段時間的股票價格數據來預測未來的價格走勢。 步驟分析 數據準備&#xff1a;獲取股票價格數…

C++ STL Map 學習學案(提高版)

C++ STL Map 學案(初中生版) 一、學習目標 深入理解 STL 中 map 容器的概念、特點和用途。熟練掌握 map 容器的基本操作,如插入、查找、刪除和遍歷元素。能夠運用 map 容器解決實際編程問題,提升邏輯思維和編程實踐能力。二、知識講解 引入 在日常生活中,我們常常會遇到…

uniapp實現人臉識別(不使用三方插件)

uniapp實現人臉識別 內容簡介功能實現上傳身份證進行人臉比對 遇到的問題 內容簡介 1.拍攝/相冊將身份證照片上傳到接口進行圖片解析 2.使用live-pusher組件拍攝人臉照片&#xff0c;上傳接口與身份證人臉進行比對 功能實現 上傳身份證 先看下效果 點擊按鈕調用chooseImage…

Evaluating Very Long-Term Conversational Memory of LLM Agents 論文

Abstract : 長期開放域對話的現有作品著重于評估不超過五個聊天會議的上下文中的模型響應。盡管LongContext大語言模型&#xff08;LLM&#xff09;和檢索增強發電&#xff08;RAG&#xff09;技術的進步&#xff0c;但在長期對話中的功效仍未得到探索。為了解決這一研究差距&a…

相對收益-固定收益組合歸因-Campisi模型

固定收益組合歸因-Campisi模型 1 Campisi模型11.1 Campisi歸因框架1.2 Campisi模型絕對收益分解1.2.1 票息收益1. 2.2 收斂收益1. 2.3 騎乘收益1. 2.4 平移收益1. 2.5 扭曲收益1. 2.6 利差收益1. 2.7 殘差收益 1.3 Campisi模型超額收益分解 2 Campisi模型22.1 分解框架2.2 模型…

IntelliJ IDEA使用經驗(十三):使用Git克隆github的開源項目

文章目錄 問題背景辦法1、設置git代理&#xff1b;2、再次克隆項目&#xff1b;3、再次按常規方式進行git克隆即可。 問題背景 由于github在國外&#xff0c;很多時候我們在使用idea克隆開源項目的時候&#xff0c;沒辦法檢出&#xff0c;提示 連接重置。 辦法 1、設置git代…

JAVA安全之Java Agent打內存馬

基本介紹 Java Agent是一種特殊的Java程序&#xff0c;它允許開發者在Java虛擬機(JVM)啟動時或運行期間通過java.lang.instrument包提供的Java標準接口進行代碼插樁&#xff0c;從而實現在Java應用程序類加載和運行期間動態修改已加載或者未加載的類&#xff0c;包括類的屬性、…

RabbitMQ 消息順序性保證

方式一&#xff1a;Consumer設置exclusive 注意條件 作用于basic.consume不支持quorum queue 當同時有A、B兩個消費者調用basic.consume方法消費&#xff0c;并將exclusive設置為true時&#xff0c;第二個消費者會拋出異常&#xff1a; com.rabbitmq.client.AlreadyClosedEx…

SQL自學,mysql從入門到精通 --- 第 14天,主鍵、外鍵的使用

1.主鍵 PRIMARY KEY 主鍵的使用 字段值不允許重復&#xff0c;且不允許賦NULL值 創建主鍵 rootmysqldb 10:11: [d1]> CREATE TABLE t3(-> name varchar(10) PRIMARY KEY,-> age int,-> class varchar(8)-> ); Query OK, 0 rows affected (0.01 sec)rootmys…

DeepSeek深度思考:客戶端(Android/iOS)架構設計指南

目標讀者&#xff1a;中高級開發者、架構師 適用場景&#xff1a;大型復雜應用開發、跨團隊協作、長期維護迭代 一、架構設計核心原則 1.模塊化&#xff08;Modularization&#xff09; 橫向拆分&#xff1a;按功能邊界劃分&#xff08;如登錄、支付、消息模塊&#xff09;縱向…

【MQ】Spring3 中 RabbitMQ 的使用與常見場景

一、初識 MQ 傳統的單體架構&#xff0c;分布式架構的同步調用里&#xff0c;無論是方法調用&#xff0c;還是 OpenFeign 難免會有以下問題&#xff1a; 擴展性差&#xff08;高耦合&#xff0c;需要依賴對應的服務&#xff0c;同樣的事件&#xff0c;不斷有新需求&#xff0…

EasyExcel 導出合并層級單元格

EasyExcel 導出合并層級單元格 一、案例 案例一 1.相同訂單號單元格進行合并 合并結果 案例二 1.相同訂單號的單元格進行合并2.相同訂單號的總數和總金額進行合并 合并結果 案例三 1.相同訂單號的單元格進行合并2.相同訂單號的商品分類進行合并3.相同訂單號的總數和總金額…

cs106x-lecture3(Autumn 2017)

打卡cs106x(Autumn 2017)-lecture3 1、streamErrors Suppose an input file named streamErrors-data.txt contains the following text: Donald Knuth M 76 Stanford U. The code below attempts to read the data from the file, but each section has a bug. Correct th…

C++模板編程——typelist的實現

文章最后給出了匯總的代碼&#xff0c;可直接運行 1. typelist是什么 typelist是一種用來操作類型的容器。和我們所熟知的vector、list、deque類似&#xff0c;只不過typelist存儲的不是變量&#xff0c;而是類型。 typelist簡單來說就是一個類型容器&#xff0c;能夠提供一…

springboot 事務管理

在Spring Boot中&#xff0c;事務管理是通過Spring框架的事務管理模塊來實現的。Spring提供了聲明式事務管理和編程式事務管理兩種方式。通常&#xff0c;我們使用聲明式事務管理&#xff0c;因為它更簡潔且易于維護。 1. 聲明式事務管理 聲明式事務管理是通過注解來實現的。…

windows通過網絡向Ubuntu發送文件/目錄

由于最近要使用樹莓派進行一些代碼練習&#xff0c;但是好多東西都在windows里或虛擬機上&#xff0c;就想將文件傳輸到樹莓派上&#xff0c;但試了發現u盤不能簡單傳送&#xff0c;就在網絡上找到了通過windows 的scp命令傳送 前提是樹莓派先開啟ssh服務&#xff0c;且Window…

字節跳動后端一面

&#x1f4cd;1. Gzip壓縮技術詳解 Gzip是一種流行的無損數據壓縮格式&#xff0c;它使用DEFLATE算法來減少文件大小&#xff0c;廣泛應用于網絡傳輸和文件存儲中以提高效率。 &#x1f680; 使用場景&#xff1a; ? 網站優化&#xff1a;通過壓縮HTML、CSS、JavaScript文件來…

Leetcode 3448. Count Substrings Divisible By Last Digit

Leetcode 3448. Count Substrings Divisible By Last Digit 1. 解題思路2. 代碼實現 題目鏈接&#xff1a;3448. Count Substrings Divisible By Last Digit 1. 解題思路 這一題的話我們走的是一個累積數組的思路。 首先&#xff0c;我們使用一個cache數組記錄下任意段數字…

三維模擬-機械臂自翻車

機械仿真 前言效果圖后續 前言 最近在研究Unity機械仿真&#xff0c;用Unity實現其運動學仿真展示的功能&#xff0c;發現一個好用的插件“MGS-Machinery-master”&#xff0c;完美的解決了Unity關節定義缺少液壓缸伸縮關節功能&#xff0c;內置了多個場景&#xff0c;講真的&…