“new出對象“原理的深層解密

在這里插入圖片描述

🎈個人主頁:🎈 :???初階牛???
🐻推薦專欄1: 🍔🍟🌯C語言初階
🐻推薦專欄2: 🍔🍟🌯C語言進階
🔑個人信條: 🌵知行合一
🍉本篇簡介:>:講解C++中的有關內存管理知識,如何new出對象?
金句分享:
?如果事與愿違,請相信另有安排.?

前言

講解C++中有關new的知識,與malloc進行對比,以及深入探索new的實現原理.

目錄

  • 前言
  • 一、malloc和new的使用
    • 1.1 new創建內置類型(int等)
    • 1.2 new創建數組
    • 1.3 創建對象
    • 1.4 異常處理
  • 二、malloc和new的區別:(面試熱門)
  • 三、new和delete的深層解密
    • 3.1 解密實現原理
    • 3.2 通過匯編指令驗證

一、malloc和new的使用

C語言階段,我們習慣使用malloc向內存申請空間,但是在C++階段,我們習慣用new在動態內存中創建對象,為什么呢?

1.1 new創建內置類型(int等)

在創建內置類型時,new只是不需要進行強轉和計算內置類型的大小,看起來更加簡潔,方便.

	//malloc申請內置類型int* p1 = (int*)malloc(sizeof(int));free(p1);//new對比int* ptr1 = new int;delete ptr1;

1.2 new創建數組

new + 對象的類型 + [個數] + (初始化的值)

new + 對象的類型 + [個數] + {num1,num2,…}

需要注意的是,連續的多個空間須使用new[]delete[]搭配

	//申請數組int* p3 = (int*)malloc(sizeof(int) * 10);//賦值for (int i = 0; i < 10; i++){p3[i] = i;}//打印for (int i = 0; i < 10; i++){cout << p3[i] << " ";}cout << endl;// new創建數組int* ptr3 = new int[10]{0,1,2,3,4,5,6,7,8,9};for (int i = 0; i < 10; i++){cout << ptr3[i] << " ";}//釋放free(p3);delete[] ptr3;

1.3 創建對象

如何使用new進行創建對象?

#include <iostream>
using namespace std;
#include<stdlib.h>class Date
{
public:Date():_year(2020),_month(6),_day(6){cout << "A()" << endl;}void print(){cout << _year << "-" << _month << "-" << _day << endl;}~Date(){cout << "~A()" << endl;free(_a);}
private:int _year;int _month;int _day;int* _a=nullptr;
};int main()
{//malloc出對象Date* d1 = (Date*)malloc(sizeof(Date));d1->print();free(d1);//new出對象Date* d2 = new Date;d2->print();delete d2;return 0;
}

運行結果:

-842150451–842150451–842150451
A()
2020-6-6
~A()

通過上段代碼我們發現,malloc只是進行開空間的操作,對象并沒有得到初始化操作.
new則是在開空間的同時,會調用對象的構造函數,將對象進行初始化.

free只是進行簡單的釋放申請的空間,如果對象中存在動態申請的成員,則無法進行釋放.
delete會在釋放申請的對象空間的同時,調用對象的析構函數,徹底的完成空間的清理工作.

1.4 異常處理

對于malloc函數,當malloc申請內存空間失敗的時候,會返回一個NULL指針.
我們通常通過判斷返回值是否為NULL來判斷是否申請成功.

	int* a = (int*)malloc(10000* sizeof(int));if (a == NULL){perror("malloc a fail");//申請失敗時,打印錯誤信息return 0;}

new失敗不會返回NULL,而是通過拋出異常.
C++中,可以使用try-catch語句來捕獲new操作符拋出的異常。new操作符在內存分配過程中如果失敗,會拋出一個bad_alloc異常。

示例代碼:

try {int* myArray = new int[10000]; // 分配一個包含10000個整數的數組// ...delete[] myArray; 
}
catch (const std::bad_alloc& e) {// 處理內存分配失敗的異常std::cout << "內存分配失敗: " << e.what() << std::endl;
}

在上述代碼中,new操作符用于分配一個包含10000個整數的數組。如果內存分配失敗,將拋出一個bad_alloc異常。catch語句塊接收這個異常,并執行相應的處理代碼。在這個示例中,異常被捕獲后會打印一條錯誤消息。

需要注意的是,catch語句塊中的參數類型應為const std::bad_alloc&,因為bad_alloc是標準異常類,它派生自std::exception,通常以常量引用的形式傳遞給異常處理代碼。

二、malloc和new的區別:(面試熱門)

C++中,mallocnew都用于在堆上分配內存,但有一些重要的區別。

  1. 語法和類型安全性mallocfree是函數,newdelete是操作符
    (1)malloc是C語言中的函數,malloc需要指定要分配的內存大小,并返回一個指向未初始化內存塊的指針。
    (2)newC++中的運算符new可以直接在創建對象時進行初始化,并返回一個指向已經構造的對象的指針。new操作符會執行類型檢查,確保分配的內存與對象類型匹配。

  2. 構造函數和析構函數調用
    (1)使用new分配內存時,會自動調用對象的構造函數進行初始化。
    (2)使用malloc分配內存時,不會調用對象的構造函數,需要手動調用構造函數初始化對象。
    (3)同樣,使用delete釋放new分配的內存時,會自動調用析構函數進行清理工作。而使用free釋放malloc分配的內存時,不會自動調用析構函數,需要手動執行清理操作。

  3. 內存大小計算
    (1)使用malloc分配內存時,需要顯式指定要分配的內存塊的大小,以字節為單位。
    (2)使用new分配單個對象時,編譯器會自動計算所需的內存大小,以對象的類型為基礎。對于數組對象,需要使用new[]delete[],同樣會自動計算所需的內存。

  4. 異常處理new在分配內存失敗時,會拋出std::bad_alloc異常,而malloc在分配內存失敗時,返回NULL指針。

  5. malloc的返回值為void*, 在使用時必須強轉,new不需要,因為new后跟的是空間的類型

總的來說,new相對于malloc提供了更高級的、更安全的內存分配方式,能夠自動調用構造函數和析構函數,執行類型檢查,并提供異常處理。因此,在C++中,推薦使用newdelete來進行動態內存分配和釋放。如果你需要使用C語言的庫或與C代碼進行交互,可以使用mallocfree

三、new和delete的深層解密

3.1 解密實現原理

學到這里,我們知道new會代用構造函數,還會拋出異常,那它究竟是怎么實現的呢?
在這里插入圖片描述

operator new的實現

void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
void *p;
while ((p = malloc(size)) == 0)//通過mallo開空間if (_callnewh(size) == 0){// report no memory// 如果申請內存失敗了,這里會拋出bad_alloc 類型異常static const std::bad_alloc nomem;_RAISE(nomem);}
return (p);
}

在這里插入圖片描述

看不懂沒關系,只需要知道operator delete調用了free函數即可

void operator delete(void *pUserData)
{_CrtMemBlockHeader * pHead;RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));if (pUserData == NULL)return;_mlock(_HEAP_LOCK);  /* block other threads */__TRY/* get a pointer to memory block header */pHead = pHdr(pUserData);/* verify block type */_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));_free_dbg( pUserData, pHead->nBlockUse );//調用了free函數__FINALLY_munlock(_HEAP_LOCK);  /* release other threads */__END_TRY_FINALLYreturn;
}

free的實現就是一個宏定義_free_dbg(p, _NORMAL_BLOCK)

#define   free(p)               _free_dbg(p, _NORMAL_BLOCK)

我們可以直接調用operator newoperator delete函數.

void test1()
{A* a1 = (A*)operator new (sizeof(A));A* a2 = (A*)malloc (sizeof(A));operator delete(a1);free(a2);
}
int main()
{test1();return 0;
}

發現operator new 的使用和malloc沒什么區別,
只是一個拋異常.
一個返回NULL.
在這里插入圖片描述

3.2 通過匯編指令驗證

void test1()
{A* a1 = new A;delete a1;
}

通過調試窗口的反匯編窗口,我們查看A* a1 = new A;對應的匯編指令:
在這里插入圖片描述
會發現,new操作符果然是調用operator new +構造函數.

查看delete操作符,由于vs編譯器進行了再封裝,我們需要進到下面這條指令里面去看:
在這里插入圖片描述

不難發現,delete操作符=調用析構函數+調用operator delete函數
在這里插入圖片描述

好的,本篇有關new操作符和delete操作符的相關知識就講到這里了,希望對大家有所幫助.
如果覺得文章有幫助的話,可以來個一鍵三連嗎?
在這里插入圖片描述

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

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

相關文章

正規的股票杠桿公司_杠桿公司排名(2023年版的)

本文將介紹一些正規的股票杠桿公司&#xff0c;并重點介紹配先查網站的特點&#xff0c;該網站是一家專業查詢實盤杠桿平臺的網站&#xff0c;提供相關信息和參考。 杠桿公司排名&#xff08;2023年版的&#xff09;&#xff1a;廣盛網、一鼎盈、尚紅網、盛多網、紅騰網、富燈…

Oracle/PL/SQL奇技淫巧之ROWNUM偽列

ROWNUM偽列 ROWNUM是一個偽列&#xff0c;它是根據每次查詢的結果動態生成的一列遞增編號&#xff0c;表示 Oracle 從表中選擇該行的順序&#xff0c;選擇的第一行ROWNUM為1&#xff0c;第二行ROWNUM為2&#xff0c;以此類推。 注意1&#xff1a; ROWNUM偽列是在WHERE子句之…

Mybatis——返回值(resultType&resultMap)詳解

之前的文章里面有對resultType和resultMap的簡單介紹這一期出點詳細的 resultType&#xff1a; 1&#xff0c;返回值為簡單類型。 直接使用resultType“類型”&#xff0c;如string&#xff0c;Integer等。 String getEmpNameById(Integer id); <!-- 指定 result…

Linux內核源碼剖析之TCP保活機制(KeepAlive)

寫在前面&#xff1a; 版本信息&#xff1a; Linux內核2.6.24&#xff08;大部分centos、ubuntu應該都在3.1。但是2.6的版本比較穩定&#xff0c;后續版本本質變化也不是很大&#xff09; ipv4 協議 https://blog.csdn.net/ComplexMaze/article/details/124201088 本文使用案例…

高級AI賦能Fortinet FortiXDR解決方案

擴展檢測和響應 (XDR&#xff1a;Extended Detection and Response) 解決方案旨在幫助組織整合分布式安全技術&#xff0c;更有效地識別和響應活動的威脅。雖然 XDR 是一種新的技術概念&#xff0c;但其構建基礎是端點檢測和響應 (EDR&#xff1a;Endpoint Detection and Respo…

代碼隨想錄算法訓練營第50天|動態規劃part11

8.16周三 123.買賣股票的最佳時機III 188.買賣股票的最佳時機IV 詳細布置 123.買賣股票的最佳時機III 題目&#xff1a;最多買賣兩次 題解&#xff1a; 1、 dp[i][0]沒有操作 &#xff08;其實我們也可以不設置這個狀態&#xff09; dp[i][1]第一次持有股票 dp[i][2]第一…

CSDN?索尼 toio?應用創意開發征集征集活動 創意公示! 入選的用戶看過來~

索尼toio?應用創意開發征集活動自開啟以來&#xff0c;收到了很多精彩的創意&#xff01;接下來&#xff0c;我們將公示入選的20個優秀創意和10個入圍創意&#xff0c;以下提到ID的小伙伴注意啦&#xff0c;你們將有機會順利進入活動的第二階段&#xff0c;注意查收你們的信箱…

javaScript:快樂學習計時器

目錄 一.前言 二.計時器 1.計時器的分類 2. 創建計時器的方式 創建間隔計時器 創建方式三種 1.匿名函數 2.使用函數直接作為計時器的執行函數 2.使用函數直接作為計時器的執行函數,用字符串的形式寫入 3.計時器的返回值 4.清除計時器 5.延遲計時器 相關代碼 一.前言 在…

Linux--實用指令與方法(部分)

下文主要是一些工作中零碎的常用指令與方法 實用指令與方法&#xff08;部分&#xff09; linux長時間保持ssh連接 這個問題的原因是&#xff1a;設置檢測時間太短&#xff0c;或者沒有保持tcp長連接。 解決步驟&#xff1a; 步驟1&#xff1a;打開sshd配置文件&#xff0…

nbcio-boot從3.0升級到3.1的出現用戶管理與數據字典bug

升級后出現 系統管理里的用戶管理出現下面問題 2023-08-17 09:44:38.902 [http-nio-8080-exec-4] [1;31mERROR[0;39m [36mo.jeecg.common.exception.JeecgBootExceptionHandler:69[0;39m - java.lang.String cannot be cast to java.lang.Long java.lang.ClassCastException:…

【JS 線性代數算法之向量與矩陣】

線性代數算法 一、向量的加減乘除1. 向量加法2. 向量減法3. 向量數乘4. 向量點積5. 向量叉積 二、矩陣的加減乘除1. 矩陣加法2. 矩陣減法3. 矩陣數乘4. 矩陣乘法 常用數學庫 線性代數是數學的一個分支&#xff0c;用于研究線性方程組及其解的性質、向量空間及其變換的性質等。在…

windows bat腳本,使用命令行增加/刪除防火墻:入站-出站,規則

常常手動設置防火墻的入站或出站規則&#xff0c;比較麻煩&#xff0c;其實可以用命令行搞定。 下面是禁用BCompare.exe連接網絡的例子&#xff1a; ECHO OFF&(PUSHD "%~DP0")&(REG QUERY "HKU\S-1-5-19">NUL 2>&1)||(powershell -Comm…

web即時通訊系統與APP即時通訊系統有什么區別?

隨著互聯網的不斷發展&#xff0c;即時通訊技術也在不斷地完善和發展&#xff0c;其中Web即時通訊系統和APP即時通訊系統成為了人們廣泛使用的兩種通訊方式。那么&#xff0c;這兩者之間究竟有什么區別呢&#xff1f;在本文中&#xff0c;我們將為您詳細介紹這兩種通訊方式的區…

如何將labelImg打包成exe

最近整理一下數據標注這塊的內容&#xff0c;在目標檢測和目標分割里面用的最多的標注工具labelimg&#xff0c;labelme labelimg主要用于目標檢測領域制作自己的數據集&#xff0c;如&#xff1a;YOLO系列目標檢測模型 labelme主要用于圖像分割領域制作自己的數據集&#xf…

如何仿寫簡易tomcat 實現思路+代碼詳細講解

仿寫之前&#xff0c;我們要搞清楚都要用到哪些技術 自定義注解&#xff0c;比如Tomcat使用的是Servlet&#xff0c;我們可以定義一個自己的MyServlet構造請求體和返回體&#xff0c;比如tomcat使用HttpRequest&#xff0c;我們可以自己定義myHttpRequestjava去遍歷一個指定目…

Structs新增接口 報錯404,找不到資源

起因&#xff1a;最近在一個古老框架structs上開發新功能&#xff0c;由于之前沒接觸過&#xff0c;故此記錄 新增接口&#xff0c; 接口類&#xff1a; Path("/A") Produces({ MediaType.APPLICATION_JSON }) public interface Money {POSTPath("/B")Resu…

數據結構——鏈表詳解

鏈表 文章目錄 鏈表前言認識鏈表單鏈表結構圖帶頭單循環鏈表結構圖雙向循環鏈表結構圖帶頭雙向循環鏈表結構圖 鏈表特點 鏈表實現(帶頭雙向循環鏈表實現)鏈表結構體(1) 新建頭節點(2) 建立新節點(3)尾部插入節點(4)刪除節點(5)頭部插入節點(6) 頭刪節點(7) 尋找節點(8) pos位置…

網絡編程socket.close/output.close/socket.shutdownOutput區別與流程分析

文章目錄 三種方法效果的區別套接字Socket關閉與釋放的區別服務器執行三種關閉操作后&#xff0c;繼續發送/接收數據會發生什么socket.shutdownOutput 關閉連接 找了半個小時沒一個說明白的帖子&#xff0c;真的折磨 三種方法效果的區別 socket.close()Socket主動禁止輸入和輸…

APP外包開發原生和H5的區別

原生開發和H5開發是兩種不同的方法&#xff0c;用于創建移動應用程序。它們具有各自的特點、優勢和劣勢&#xff0c;適用于不同的應用場景。以下是原生開發和H5開發之間的一些主要區別&#xff0c;希望對大家有所幫助。北京木奇移動技術有限公司&#xff0c;專業的軟件外包開發…

DELETE 與TRUNCATE區別

DELETE 與TRUNCATE區別 要清空 PostgreSQL 中的表數據&#xff0c;可以使用 DELETE 或 TRUNCATE 語句。下面是兩種方法的示例&#xff1a; 使用 DELETE 語句清空表數據&#xff1a; DELETE FROM 表名;例如&#xff0c;要清空名為 users 的表數據&#xff1a; DELETE FROM u…