某日二師兄參加XXX科技公司的C++工程師開發崗位第30面:
面試官:什麼是空指標?
二師兄:一般我們將等於
0
/NULL
/nullptr
的指標稱為空指標。空指標不能被解除參照,但是可以對空指標取地址。
int* p = nullptr; //空指標
*p = 42; //空指標不可以解除參照
int** pp = &p //空指標可以取地址
面試官:你知道
0/NULL/nullptr
三者之間的區別嗎?二師兄:雖然三者都能定義空指標,但三者型別不同。
二師兄:
0
是int
型別,NULL
在g++下是一個宏定義,而nullptr
是有型別的;
#define NULL ((void *)0)
typedef decltype(nullptr) nullptr_t;
sizeof(0);// 4
sizeof(NULL);//8
sizeof(nullptr);//8
二師兄:在函數過載時,會根據實參的型別選擇過載函數:
#include <iostream>
void fun(int) {std::cout << "int" << std::endl;}
void fun(int*) {std::cout << "int*" << std::endl;}
void fun(nullptr_t) {std::cout << "nullptr_t" << std::endl;}
int main(int argc, char const *argv[])
{
fun(0); //編譯通過,匹配fun(int)
fun(NULL); //編譯失敗,可以匹配 fun(int) fun(int*) fun(nullptr_t)
fun(nullptr); //編譯成功,匹配fun(nullptr_t)
return 0;
}
二師兄:在C++11之後,建議使用
nullptr
定義空指標,因為它時有型別的,編譯器能夠對它進行型別檢查。面試官:什麼是野指標?
二師兄:野指標突出一個野字,這個野就是狀態未知的。它可能指向一塊未知的區域:
int* p; //野指標,指標未初始化
*p = 42; //對野指標解除參照,未定義的操作
面試官:什麼是垂懸指標?
二師兄:垂懸指標是指指標指向的內容已被釋放,指標指向的物件的生命週期已結束。
int* p = new int(42);
delete p;
*p = 1024; //垂懸指標,指標指向的物件已被釋放
int* p = nullptr;
{
int i = 42;
p = &i;
}
*p = 1024; //垂懸指標,指向的物件的生命週期已結束
面試官:如何解決空指標、野指標、垂懸指標帶來的問題?
二師兄:主要可以從有以下幾點入手:
1.在解除參照指標之前,要判斷指標是否為空。(解決空指標解除參照問題)
2.對於定義的指標,一定要進行初始化(
=nullptr
)。(解決野指標問題)3.對於釋放過內容的指標,立即將指標置為
nullptr
。(解決垂懸指標、指標二次釋放問題)4.要注意長生命週期的指標不能指向短生命週期的物件。(解決垂懸指標問題)
5.C++11之後使用智慧指標。
面試官:好的。那你知道什麼是記憶體漏失(
memory leak
)嗎?二師兄:記憶體漏失是指分配的記憶體空間沒有被正確釋放的情況。常見的情況有
malloc
沒有free
,new
沒有delete
,new[]
和delete
混用。面試官:如何防範記憶體漏失問題?
二師兄:最簡單的辦法是使用資源獲取即初始化(
RAII
)技術將資源放在類中管理,在類構造時獲取資源(malloc/new
),在類的解構函式中釋放資源(free/delete
),使用C++的構造和解構機制保證資源的正確申請和釋放。二師兄:我們常用的
std::shared_ptr
和std::unique_ptr
及std::lock_guard
就是採用這種技術管理資源。面試官:最後一個問題,如何查詢程式中是否出現了記憶體漏失?
二師兄:只要有兩種方法:
1.自己動手:把所有使用
malloc/free
的地方改成new/delete
,過載全域性的new
和delete
,並加入申請和釋放記憶體容量的統計邏輯。2.採用工具:可以使用諸如
Valgrind
(在Linux上)或Dr. Memory
(在Windows上)等記憶體偵錯工具來檢測記憶體漏失。這些工具可以在執行程式時檢測記憶體漏失,並提供詳細的報告和偵錯資訊。面試官:好的。今天的面試結束,請等訊息。
今天的面試到這裡就結束了,祝大家週末愉快~
關注我,帶你21天「精通」C++!(狗頭)