二十万字C/C++、嵌入式软开面试题全集宝典六
目錄
101、 字節(jié)對齊有什么作用?
102、 C語言中#pragma用法
103、 new和malloc的區(qū)別?
104、 malloc/calloc/realloc三者之間的區(qū)別?
105、 delete p;與delete[]p,allocator
106、 new和delete的實現(xiàn)原理,delete是如何知道釋放內(nèi)存的大小?
107、 malloc申請的存儲空間能用delete釋放嗎
108、 函數(shù)參數(shù)入棧的順序
109、 堆和棧區(qū)別
110、 堆與棧的優(yōu)點和缺點
111、 內(nèi)核空間 虛擬內(nèi)存管理
112、 malloc與free的實現(xiàn)原理?
113、 malloc、realloc、calloc的區(qū)別
114、 __stdcall和__cdecl的區(qū)別?
115、 手寫字符串函數(shù) strcat, strcpy, strncpy, memset, memcpy實現(xiàn)
116、 使用智能指針管理內(nèi)存資源,RAII
117、 手寫實現(xiàn)智能指針類
118、 結(jié)構(gòu)體變量比較是否相等
119、 位運算
120、 函數(shù)調(diào)用過程棧的變化,返回值和參數(shù)變量哪個先入棧?
?
101、 字節(jié)對齊有什么作用?
字節(jié)對齊的作用不僅是便于cpu快速訪問,同時合理的利用字節(jié)對齊可以有效地節(jié)省存儲空間。
編譯器中提供了#pragma pack(n)來設(shè)定變量以n字節(jié)對齊方式。n字節(jié)對齊就是說變量存放的起始地址的偏移量有兩種情況:第一、如果n大于等于該變量所占用的字節(jié)數(shù),那么偏移量必須滿足默認(rèn)的對齊方式,第二、如果n小于該變量的類型所占用的字節(jié)數(shù),那么偏移量為n的倍數(shù),不用滿足默認(rèn)的對齊方式。
?
102、 C語言中#pragma用法
1.#pragma message
#pragma message("消息文本") 當(dāng)編譯器遇到這條指令時,就在編譯輸出窗口中將消息文本打印出來。
2.#pragma code_seg
#pragma code_seg(["section-name"["section-class"]])
它能夠設(shè)置程序中函數(shù)代碼存放的代碼段。當(dāng)我們開發(fā)驅(qū)動程序時便就會使用到它。
3.#pragma once
只要在頭文件的最開始加入這條指令就能夠頭文件被編譯一次。
4.#pragma hdrstop
表示編譯頭文件到此為止,后面的頭文件不進(jìn)行預(yù)編譯。
5.#pragma resouce
#pragma resouce"*.dfm"表示*.dfm文件中的資源加入工程。*.dfm中包括了外觀定義。
6.#pragma warning
#pragma warning (disable:4507 34; once:4385; error:164) 等價于
#pragma warning (disable:4507 34) //不顯示4507和30號警告信息
#pragma warning (once:4385) //4358號警告信息僅報告一次
#pragma warning (error:164) //把164號警告信息作為一種錯誤
7.#pragma comment
#pragma comment(...) 該指令將一個注釋放入一個對象文件或可執(zhí)行文件中,常用lib關(guān)鍵字幫我們鏈入一個庫文件。
如:#pragma comment(lib,"user32.lib") 該指令用來將user32.lib庫文件加入到本工程中。
8. #pragma pack
這條指令主要用作改變編譯器的默認(rèn)對齊方式。
103、 new和malloc的區(qū)別?
1.new/delete是C++關(guān)鍵字,需要編譯器支持。malloc/free是庫函數(shù),需要頭文件支持;
2.使用new操作符申請內(nèi)存分配時無須指定內(nèi)存塊的大小,編譯器會根據(jù)類型信息自行計算。而malloc則需要顯式地指出所需內(nèi)存的尺寸。
3.new操作符內(nèi)存分配成功時,返回的是對象類型的指針,類型嚴(yán)格與對象匹配,無須進(jìn)行類型轉(zhuǎn)換,故new是符合類型安全性的操作符。而malloc內(nèi)存分配成功則是返回void * ,需要通過強(qiáng)制類型轉(zhuǎn)換將void*指針轉(zhuǎn)換成我們需要的類型。
4.new內(nèi)存分配失敗時,會拋出bac_alloc異常。malloc分配內(nèi)存失敗時返回NULL。
5.new會先調(diào)用operator new函數(shù),申請足夠的內(nèi)存(通常底層使用malloc實現(xiàn))。然后調(diào)用類型的構(gòu)造函數(shù),初始化成員變量,最后返回自定義類型指針。delete先調(diào)用析構(gòu)函數(shù),然后調(diào)用operator delete函數(shù)釋放內(nèi)存(通常底層使用free實現(xiàn))。malloc/free是庫函數(shù),只能動態(tài)的申請和釋放內(nèi)存,無法強(qiáng)制要求其做自定義類型對象構(gòu)造和析構(gòu)工作。
104、 malloc/calloc/realloc三者之間的區(qū)別?
1)void *malloc(size_t size);
size表示要分配的字節(jié)數(shù),其中要檢測空間是否開辟成功,開辟失敗時返回0。
作用:在內(nèi)存中分配一個元素被初始化為0的數(shù)組。
2)void *calloc(size_t num, size_t size);
num表示元素的個數(shù),size表示每個元素的大小
返回值:返回一個指向所分配空間的void指針。
作用:重新分配內(nèi)存塊
3)void *realloc(void* memblock,size_t size);
memblock指向原先分配的內(nèi)存塊,size表示新的內(nèi)存塊的字節(jié)大小。
返回值:返回一個指向重新分配(可能移動了)的內(nèi)存塊的大小。
注意:堆上的內(nèi)存需要用戶自己來管理,動態(tài)malloc/calloc/realloc的空間,必須free掉,否則會造成內(nèi)存泄漏
105、 delete p;與delete[]p,allocator
1.動態(tài)數(shù)組管理new一個數(shù)組時,[]中必須是一個整數(shù),但是不一定是常量整數(shù),普通數(shù)組必須是一個常量整數(shù);
2.new動態(tài)數(shù)組返回的并不是數(shù)組類型,而是一個元素類型的指針;
3.delete[]時,數(shù)組中的元素按逆序的順序進(jìn)行銷毀;
4.new在內(nèi)存分配上面有一些局限性,new的機(jī)制是將內(nèi)存分配和對象構(gòu)造組合在一起,同樣的,delete也是將對象析構(gòu)和內(nèi)存釋放組合在一起的。allocator將這兩部分分開進(jìn)行,allocator申請一部分內(nèi)存,不進(jìn)行初始化對象,只有當(dāng)需要的時候才進(jìn)行初始化操作。
106、 new和delete的實現(xiàn)原理,delete是如何知道釋放內(nèi)存的大小?
1.new簡單類型直接調(diào)用operator new分配內(nèi)存;而對于復(fù)雜結(jié)構(gòu),先調(diào)用operator new分配內(nèi)存,然后在分配的內(nèi)存上調(diào)用構(gòu)造函數(shù);對于簡單類型,new[]計算好大小后調(diào)用operator new;對于復(fù)雜數(shù)據(jù)結(jié)構(gòu),new[]先調(diào)用operator new[]分配內(nèi)存,然后在p的前四個字節(jié)寫入數(shù)組大小n,然后調(diào)用n次構(gòu)造函數(shù),針對復(fù)雜類型,new[]會額外存儲數(shù)組大小;
○1new表達(dá)式調(diào)用一個名為operator new(operator new[])函數(shù),分配一塊足夠大的、原始的、未命名的內(nèi)存空間;
○2編譯器運行相應(yīng)的構(gòu)造函數(shù)以構(gòu)造這些對象,并為其傳入初始值;
○3對象被分配了空間并構(gòu)造完成,返回一個指向該對象的指針。
2.delete簡單數(shù)據(jù)類型默認(rèn)只是調(diào)用free函數(shù);復(fù)雜數(shù)據(jù)類型先調(diào)用析構(gòu)函數(shù)再調(diào)用operator delete;針對簡單類型,delete和delete[]等同。假設(shè)指針p指向new[]分配的內(nèi)存。因為要4字節(jié)存儲數(shù)組大小,實際分配的內(nèi)存地址為[p-4],系統(tǒng)記錄的也是這個地址。delete[]實際釋放的就是p-4指向的內(nèi)存。而delete會直接釋放p指向的內(nèi)存,這個內(nèi)存根本沒有被系統(tǒng)記錄,所以會崩潰。
3.需要在 new [] 一個對象數(shù)組時,需要保存數(shù)組的維度,C++ 的做法是在分配數(shù)組空間時多分配了 4 個字節(jié)的大小,專門保存數(shù)組的大小,在 delete [] 時就可以取出這個保存的數(shù),就知道了需要調(diào)用析構(gòu)函數(shù)多少次了。
107、 malloc申請的存儲空間能用delete釋放嗎
不能,malloc /free主要為了兼容C,new和delete 完全可以取代malloc /free的。malloc /free的操作對象都是必須明確大小的。而且不能用在動態(tài)類上。new 和delete會自動進(jìn)行類型檢查和大小,malloc/free不能執(zhí)行構(gòu)造函數(shù)與析構(gòu)函數(shù),所以動態(tài)對象它是不行的。當(dāng)然從理論上說使用malloc申請的內(nèi)存是可以通過delete釋放的。不過一般不這樣寫的。而且也不能保證每個C++的運行時都能正常。
108、 函數(shù)參數(shù)入棧的順序
○1大多數(shù)編譯器中,參數(shù)是從右向左?棧(原因在于采?這種順序,是為了讓程序員在使?C/C++的“函數(shù)參數(shù)?度可變”這個特性時更?便。如果是從左向右壓棧,第?個參數(shù)(即描述可變參數(shù)表各變量類型的那個參數(shù))將被放在棧底,由于可變參的函數(shù)第?步就需要解析可變參數(shù)表的各參數(shù)類型,即第?步就需要得到上述參數(shù),因此,將它放在棧底是很不方便的。)
○2本次函數(shù)調(diào)用結(jié)束時,局部變量先出棧,然后是參數(shù),最后是棧頂指針最開始存放的地址,程序由該點繼續(xù)運?,不會產(chǎn)生碎?。
109、 堆和棧區(qū)別
1.管理方式:
○1棧由操作系統(tǒng)自動分配釋放,無需我們手動控制,無需我們手工控制,?般保存的是局部變量和函數(shù)參數(shù)等。
○2堆由程序員管理,需要?動 new malloc delete free 進(jìn)?分配和回收,如果不進(jìn)?回收的話,會造成內(nèi)存泄漏的問題。
2.空間大小:一般來講在32位系統(tǒng)下,堆內(nèi)存可以達(dá)到4G的空間,從這個角度來看堆內(nèi)存幾乎是沒有什么限制的。但是對于棧來講,一般都是有一定的空間大小的,例如,在VC6下面,默認(rèn)的棧空間大小是1M(好像是,記不清楚了)。當(dāng)然,我們可以修改: 打開工程,依次操作菜單如下:Project->Setting->Link,在Category 中選中Output,然后在Reserve中設(shè)定堆棧的最大值和commit。 注意:reserve最小值為4Byte;commit是保留在虛擬內(nèi)存的頁文件里面,它設(shè)置的較大會使棧開辟較大的值,可能增加內(nèi)存的開銷和啟動時間。
3.碎片問題:對于堆來講,頻繁的new/delete勢必會造成內(nèi)存空間的不連續(xù),從而造成大量的碎片,使程序效率降低。對于棧來講,則不會存在這個問題,因為棧是先進(jìn)后出的隊列,他們是如此的一一對應(yīng),以至于永遠(yuǎn)都不可能有一個內(nèi)存塊從棧中間彈出,在他彈出之前,在他上面的后進(jìn)的棧內(nèi)容已經(jīng)被彈出,詳細(xì)的可以參考數(shù)據(jù)結(jié)構(gòu),這里我們就不再一一討論了。
4.生長方向:
○1對于棧來講,是連續(xù)的內(nèi)存空間,它的生長方向是向下的,是向著內(nèi)存地址減小的方向增長。比如在函數(shù)調(diào)?的時候,首先?棧的主函數(shù)的下?條可執(zhí)?指令的地址,然后是函數(shù)的各個參數(shù)。
○2對于堆來講,不連續(xù)的空間,實際上系統(tǒng)中有?個空閑鏈表,生長方向是向上的,也就是向著內(nèi)存地址增加的方向,空間交?,較為靈活。
;當(dāng)有程序申請的時候,系統(tǒng)遍歷空閑鏈表找到第?個?于等于申請??的空間分配給程序,?般在分配程序的時候,也會空間頭部寫?內(nèi)存??,?便 delete 回收空間??。當(dāng)然如果有剩余的,也會將剩余的插?到空閑鏈表中,這也是產(chǎn)?內(nèi)存碎?的原因。
5.分配方式:堆都是動態(tài)分配的,沒有靜態(tài)分配的堆。棧有2種分配方式:靜態(tài)分配和動態(tài)分配。靜態(tài)分配是編譯器完成的,比如局部變量的分配。動態(tài)分配由alloca函數(shù)進(jìn)行分配,但是棧的動態(tài)分配和堆是不同的,它的動態(tài)分配是由編譯器進(jìn)行釋放,無需我們手工實現(xiàn)。
6.分配效率:棧是機(jī)器系統(tǒng)提供的數(shù)據(jù)結(jié)構(gòu),計算機(jī)會在底層對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執(zhí)行,這就決定了棧的效率比較高。堆則是C/C++函數(shù)庫提供的,它的機(jī)制是很復(fù)雜的,例如為了分配一塊內(nèi)存,庫函數(shù)會按照一定的算法(具體的算法可以參考數(shù)據(jù)結(jié)構(gòu)/操作系統(tǒng))在堆內(nèi)存中搜索可用的足夠大小的空間,如果沒有足夠大小的空間(可能是由于內(nèi)存碎片太多),就有可能調(diào)用系統(tǒng)功能去增加程序數(shù)據(jù)段的內(nèi)存空間,這樣就有機(jī)會分到足夠大小的內(nèi)存,然后進(jìn)行返回。顯然,堆的效率比棧要低得多。
110、 堆與棧的優(yōu)點和缺點
1.堆的優(yōu)缺點:堆得優(yōu)點就是可以動態(tài)分配內(nèi)存大小,生存期也不必告訴編譯器,因為它是在運行中動態(tài)分配內(nèi)存的;缺點就是由于是在運行時動態(tài)分配內(nèi)存的,所以讀取速度較慢。
2.棧的優(yōu)缺點:棧的優(yōu)點就是讀取速度快,而且數(shù)據(jù)可以共享;缺點就是存在于棧中的數(shù)據(jù)大小及周期必須是確定的,缺乏靈活性。
111、 內(nèi)核空間 虛擬內(nèi)存管理
1.虛擬內(nèi)存管理負(fù)責(zé)從進(jìn)程的虛擬地址空間分配虛擬頁,sys_brk負(fù)責(zé)用來擴(kuò)大或收縮堆,sys_mmap負(fù)責(zé)從內(nèi)存映射區(qū)域分配虛擬頁,sys_munmap用來釋放虛擬頁。
2.進(jìn)程第一次訪問虛擬頁的時候觸發(fā)頁處理異常,直接從頁處理申請物理內(nèi)存,然后映射到虛擬內(nèi)存的頁表。
3.頁分配器負(fù)責(zé)分配物理頁,當(dāng)前使用的頁分配器是伙伴分配器。內(nèi)核空間提供把頁劃分為小內(nèi)存塊分配的塊分配器,提供分配內(nèi)存的接口kmalloc(),和釋放內(nèi)存的接口kfree()。
4.不連續(xù)頁分配器提供分配內(nèi)存的接口vmalloc()和釋放內(nèi)存接口vfree(),在內(nèi)存碎片化的時候,申請連續(xù)物理頁的成功率很低,可以申請不連續(xù)的物理頁,映射到連續(xù)的虛擬頁,即虛擬地址連續(xù),頁物理地址不連續(xù)。
112、 malloc與free的實現(xiàn)原理?
malloc采用的是內(nèi)存池的管理方式(ptmalloc),ptmalloc 采用邊界標(biāo)記法將內(nèi)存劃分成很多塊,從而對內(nèi)存的分配與回收進(jìn)行管理。
為了內(nèi)存分配函數(shù)malloc的高效性,ptmalloc會預(yù)先向操作系統(tǒng)申請一塊內(nèi)存供用戶使用,當(dāng)我們申請和釋放內(nèi)存的時候,ptmalloc會將這些內(nèi)存管理起來,并通過一些策略來判斷是否將其回收給操作系統(tǒng)。
這樣做的最大好處就是,使用戶申請和釋放內(nèi)存的時候更加高效,避免產(chǎn)生過多的內(nèi)存碎片。
1.在標(biāo)準(zhǔn)C庫中,提供了malloc/free函數(shù)分配釋放內(nèi)存,這兩個函數(shù)底層是由brk、mmap、,munmap這些系統(tǒng)調(diào)用實現(xiàn)的;
2.brk是將數(shù)據(jù)段(.data)的最高地址指針_edata往高地址推,mmap是在進(jìn)程的虛擬地址空間中(堆和棧中間,稱為文件映射區(qū)域的地方)找一塊空閑的虛擬內(nèi)存。這兩種方式分配的都是虛擬內(nèi)存,沒有分配物理內(nèi)存。在第一次訪問已分配的虛擬地址空間的時候,發(fā)生虛擬中斷,操作系統(tǒng)負(fù)責(zé)分配物理內(nèi)存,然后建立虛擬內(nèi)存和物理內(nèi)存之間的映射關(guān)系;
3.malloc小于128k的內(nèi)存,使用brk分配內(nèi)存,將_edata往高地址推;malloc大于128k的內(nèi)存,使用mmap分配內(nèi)存,在堆和棧之間找一塊空閑內(nèi)存分配;brk分配的內(nèi)存需要等到高地址內(nèi)存釋放以后才能釋放,而mmap分配的內(nèi)存可以單獨釋放。當(dāng)最高地址空間的空閑內(nèi)存超過128K(可由M_TRIM_THRESHOLD選項調(diào)節(jié))時,執(zhí)行內(nèi)存緊縮操作(trim)。在上一個步驟free的時候,發(fā)現(xiàn)最高地址空閑內(nèi)存超過128K,于是內(nèi)存緊縮。
4.malloc是從堆里面申請內(nèi)存,也就是說函數(shù)返回的指針是指向堆里面的一塊內(nèi)存。操作系統(tǒng)中有一個記錄空閑內(nèi)存地址的鏈表。當(dāng)操作系統(tǒng)收到程序的申請時,就會遍歷該鏈表,然后就尋找第一個空間大于所申請空間的堆結(jié)點,然后就將該結(jié)點從空閑結(jié)點鏈表中刪除,并將該結(jié)點的空間分配給程序。
113、 malloc、realloc、calloc的區(qū)別
1.malloc函數(shù)
void* malloc(unsigned int num_size);
int *p = malloc(20*sizeof(int));申請20個int類型的空間;
2.calloc函數(shù)
void* calloc(size_t n,size_t size);
int *p = calloc(20, sizeof(int));
省去了人為空間計算;malloc申請的空間的值是隨機(jī)初始化的,calloc申請的空間的值是初始化為0的;
3.realloc函數(shù)
void realloc(void *p, size_t new_size);
給動態(tài)分配的空間分配額外的空間,用于擴(kuò)充容量。
114、 __stdcall和__cdecl的區(qū)別?
1.__stdcall
__stdcall是函數(shù)恢復(fù)堆棧,只有在函數(shù)代碼的結(jié)尾出現(xiàn)一次恢復(fù)堆棧的代碼;在編譯時就規(guī)定了參數(shù)個數(shù),無法實現(xiàn)不定個數(shù)的參數(shù)調(diào)用;
2.__cdecl
__cdecl是調(diào)用者恢復(fù)堆棧,假設(shè)有100個函數(shù)調(diào)用函數(shù)a,那么內(nèi)存中就有100端恢復(fù)堆棧的代碼;可以不定參數(shù)個數(shù);每一個調(diào)用它的函數(shù)都包含清空堆棧的代碼,所以產(chǎn)生的可執(zhí)行文件大小會比調(diào)用__stacall函數(shù)大。
115、 手寫字符串函數(shù) strcat, strcpy, strncpy, memset, memcpy實現(xiàn)
1. strcat
頭文件:#include <string.h>
用法:函數(shù)原型如下
char *strcat(char *dst, char const *src);
strcat 函數(shù)要求 dst 參數(shù)原先已經(jīng)包含了一個字符串(可以是空字符串)。它找到這個字符串的末尾,并把 src 字符串的一份拷貝添加到這個位置。如果 src 和 dst 的位置發(fā)生重疊,其結(jié)果是未定義的。編程者需要保證目標(biāo)字符數(shù)組剩余的空間足以保存整個字符串。
2. strcpy
頭文件:#include <string.h>
用法:strcpy 的函數(shù)原型如下:
char *strcpy(char *dst, const char *src);
函數(shù)把參數(shù) src 字符串復(fù)制到 dst 參數(shù),dst 字符串的結(jié)束符也會復(fù)制,如果參數(shù) src 和 dst 在內(nèi)存中出現(xiàn)疊,其結(jié)果是未定義的。由于 dst 參數(shù)將進(jìn)行修改,所以它必須是個字符串?dāng)?shù)組或者是一個指向動態(tài)內(nèi)存分配的數(shù)組指針,不能使用字符串常量。
需要注意的是:程序員必須保證目標(biāo)字符串?dāng)?shù)組的空間足以容納需要復(fù)制的字符串。如果多余的字符串比數(shù)組長,多余的字符仍被復(fù)制,它們將覆蓋原先存儲于數(shù)組后面的內(nèi)存空間。
3.memcpy
頭文件:#include <string.h>
用法:memcpy 提供了一般內(nèi)存的復(fù)制,即memcpy對于需要復(fù)制的內(nèi)容沒有限制,用途更廣泛。
void *memcpy(void *dst, const void *src, size_t length);
從 src 所指的內(nèi)存地址的起始位置開始,拷貝n個字節(jié)的數(shù)據(jù)到 dest 所指的內(nèi)存地址的起始位置。你可以用這種方法復(fù)制任何類型的值(例如:int,double,結(jié)構(gòu)或結(jié)構(gòu)數(shù)組),如果src和dst以任何形式出現(xiàn)了重疊,它的結(jié)果將是未定義的。
實現(xiàn)代碼:
4.strcpy 和 memcpy 的主要區(qū)別:
復(fù)制的內(nèi)容不同。strcpy只能復(fù)制字符串,而memcpy可以復(fù)制任意內(nèi)容,例如字符數(shù)組、整型、結(jié)構(gòu)體、類等。
復(fù)制的方法不同。strcpy不需要指定長度,它遇到被復(fù)制字符的串結(jié)束符"\0"才結(jié)束,所以容易溢出。memcpy則是根據(jù)其第3個參數(shù)決定復(fù)制的長度,遇到'\0'并不結(jié)束。
用途不同。通常在復(fù)制字符串時用strcpy,而需要復(fù)制其他類型數(shù)據(jù)時則一般用memcpy;
5.strncpy
頭文件:#include <string.h>
函數(shù)原型如下:
char *strncpy(char *dst, char const *src, size_t len);
strncpy把源字符串的字符復(fù)制到目標(biāo)數(shù)組,它總是正好向 dst 寫入 len 個字符。如果 strlen(src) 的值小于 len,dst 數(shù)組就用額外的 NUL 字節(jié)填充到 len 長度。如果 strlen(src)的值大于或等于 len,那么只有 len 個字符被復(fù)制到dst中。這里需要注意它的結(jié)果將不會以NUL字節(jié)結(jié)尾。
實現(xiàn)代碼:
5. memset
頭文件:#include <string.h>
函數(shù)原型如下:
void *memset(void *a, int ch, size_t length);
將參數(shù)a所指的內(nèi)存區(qū)域前l(fā)ength個字節(jié)以參數(shù)ch填入,然后返回指向a的指針。在編寫程序的時候,若需要將某一數(shù)組作初始化,memset()會很方便。
實現(xiàn)代碼:
116、 使用智能指針管理內(nèi)存資源,RAII
1.RAII全稱是“Resource Acquisition is Initialization”,直譯過來是“資源獲取即初始化”,也就是說在構(gòu)造函數(shù)中申請分配資源,在析構(gòu)函數(shù)中釋放資源。因為C++的語言機(jī)制保證了,當(dāng)一個對象創(chuàng)建的時候,自動調(diào)用構(gòu)造函數(shù),當(dāng)對象超出作用域的時候會自動調(diào)用析構(gòu)函數(shù)。所以,在RAII的指導(dǎo)下,我們應(yīng)該使用類來管理資源,將資源和對象的生命周期綁定。
2.智能指針(std::shared_ptr和std::unique_ptr)即RAII最具代表的實現(xiàn),使用智能指針,可以實現(xiàn)自動的內(nèi)存管理,再也不需要擔(dān)心忘記delete造成的內(nèi)存泄漏。毫不夸張的來講,有了智能指針,代碼中幾乎不需要再出現(xiàn)delete了。
117、 手寫實現(xiàn)智能指針類
1.智能指針是一個數(shù)據(jù)類型,一般用模板實現(xiàn),模擬指針行為的同時還提供自動垃圾回收機(jī)制。它會自動記錄SmartPointer<T*>對象的引用計數(shù),一旦T類型對象的引用計數(shù)為0,就釋放該對象。除了指針對象外,我們還需要一個引用計數(shù)的指針設(shè)定對象的值,并將引用計數(shù)計為1,需要一個構(gòu)造函數(shù)。新增對象還需要一個構(gòu)造函數(shù),析構(gòu)函數(shù)負(fù)責(zé)引用計數(shù)減少和釋放內(nèi)存。通過覆寫賦值運算符,才能將一個舊的智能指針賦值給另一個指針,同時舊的引用計數(shù)減1,新的引用計數(shù)加1
2.一個構(gòu)造函數(shù)、拷貝構(gòu)造函數(shù)、復(fù)制構(gòu)造函數(shù)、析構(gòu)函數(shù)、移走函數(shù);
118、 結(jié)構(gòu)體變量比較是否相等
1.重載了 “==” 操作符
struct foo { int a; int b; bool operator==(const foo& rhs) // 操作運算符重載 { return( a == rhs.a) && (b == rhs.b);} };
2.元素的話,一個個比;
3.指針直接比較,如果保存的是同一個實例地址,則(p1==p2)為真;
119、 位運算
若一個數(shù)m滿足 m = 2^n;那么k%m=k&(m-1);
位與相關(guān)性質(zhì)和計算一個數(shù)的二進(jìn)制表示中有多少個1的做法:
https://blog.csdn.net/qq_41687938/article/details/117324467
120、 函數(shù)調(diào)用過程棧的變化,返回值和參數(shù)變量哪個先入棧?
1、調(diào)用者函數(shù)把被調(diào)函數(shù)所需要的參數(shù)按照與被調(diào)函數(shù)的形參順序相反的順序壓入棧中,即:從右向左依次把被調(diào)函數(shù)所需要的參數(shù)壓入棧;
2、調(diào)用者函數(shù)使用call指令調(diào)用被調(diào)函數(shù),并把call指令的下一條指令的地址當(dāng)成返回地址壓入棧中(這個壓棧操作隱含在call指令中);
3、在被調(diào)函數(shù)中,被調(diào)函數(shù)會先保存調(diào)用者函數(shù)的棧底地址(push ebp),然后再保存調(diào)用者函數(shù)的棧頂?shù)刂?即:當(dāng)前被調(diào)函數(shù)的棧底地址(mov ebp,esp);
4、在被調(diào)函數(shù)中,從ebp的位置處開始存放被調(diào)函數(shù)中的局部變量和臨時變量,并且這些變量的地址按照定義時的順序依次減小,即:這些變量的地址是按照棧的延伸方向排列的,先定義的變量先入棧,后定義的變量后入棧;
總結(jié)
以上是生活随笔為你收集整理的二十万字C/C++、嵌入式软开面试题全集宝典六的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Pytorch中参数和模型的保存与读取
- 下一篇: 二十万字C/C++、嵌入式软开面试题全集