百度不問我項目,全程基礎拷打,真扎心!
大家好,我是小林。
今天分享一位同學百度實習一面的面經,技術棧是 C++,由于項目沒什么亮點,所以大部分內容都是在問 C++ 的問題,沒怎么問項目問題。
操作系統
對new和malloc的理解
new和malloc都是動態內存分配函數。其中,new是C++中的操作符,malloc是C語言中的函數。new會調用對象的構造函數,而malloc不會。使用new可以簡化代碼,并且更加類型安全。
補充:
new和malloc區別:
- 分配內存的位置:malloc是從堆上動態分配內存,new是從自由存儲區為對象動態分配內存。自由存儲區的位置取決于operator new的實現。自由存儲區不僅可以為堆,還可以是靜態存儲區,這都看operator new在哪里為對象分配內存。
- 返回類型安全性:malloc內存分配成功后返回void*,然后再強制類型轉換為需要的類型;new操作符分配內存成功后返回與對象類型相匹配的指針類型;因此new是符合類型安全的操作符。
- 內存分配失敗返回值:malloc內存分配失敗后返回NULL。new分配內存失敗則會拋異常(bac_alloc)。
- 分配內存的大小的計算:使用new操作符申請內存分配時無須指定內存塊的大小,編譯器會根據類型信息自行計算,而malloc則需要顯式地指出所需內存的尺寸。
- 是否可以被重載:opeartor new /operator delete可以被重載。而malloc/free則不能重載。
new是在內存上哪一塊去分配的內存
堆
補充:
new所申請的內存區域在C++中稱為自由存儲區。很多編譯器的new/delete都是以malloc/free為基礎來實現的,所以通常都是借由堆實現來實現自由存儲,這時候就可以說new所申請的內存區域在堆上。
如果new內存失敗了會是怎么樣?
會拋出std::bad_alloc異常。
補充:
如果加上std::nothrow關鍵字,A* p = new (std::nothrow) A;,new 就不會拋出異常而是會返回空指針。
析構函數為什么通常是會做成一個虛函數呢
如果一個類有虛函數,就應該為其定義一個虛析構函數。這是因為在使用delete操作符釋放一個指向派生類對象的基類指針時,如果基類的析構函數不是虛函數,那么只會調用基類的析構函數,而不會調用派生類的析構函數,這樣就會導致內存泄漏和未定義行為的問題。通過將析構函數定義為虛函數,可以確保在釋放派生類對象時,先調用派生類的析構函數,再調用基類的析構函數,從而避免內存泄漏和未定義行為的問題。
線程和進程有什么區別
進程是程序在操作系統中的一次執行過程,它擁有獨立的地址空間和系統資源。線程是進程中的一個執行單元,同一進程內的多個線程共享相同的地址空間和系統資源。
補充:
- 進程是資源調度的基本單位,運行一個可執行程序會創建一個或多個進程,進程就是運行起來的可執行程序;線程是程序執行的基本單位,每個進程中都有唯一的主線程,且只能有一個,主線程和進程是相互依存的關系,主線程結束進程也會結束。
- 每個進程有自己的獨立地址空間,不與其他進程分享;一個進程里可以有多個線程,彼此共享同一個地址空間。堆內存、文件、套接字等資源都歸進程管理,同一個進程里的多個線程可以共享使用。每個進程占用的內存和其他資源,會在進程退出或被殺死時返回給操作系統。
- 并發應用開發可以用多進程或多線程的方式。多線程由于可以共享資源,效率較高;反之,多進程(默認)不共享地址空間和資源,開發較為麻煩,在需要共享數據時效率也較低。但多進程安全性較好,在某一個進程出問題時,其他進程一般不受影響;而在多線程的情況下,一個線程執行了非法操作會導致整個進程退出。
右值引用有什么作用
沒用過
補充:
- 右值引用是C++11引入的特性,它是指對右值進行引用的一種方式。右值引用的作用主要有兩個:
- 可以通過右值引用來實現移動語義。移動語義可以在不進行深拷貝的情況下,將對象的資源所有權從一個對象轉移到另一個對象,從而提高代碼的效率。
- 右值引用還可以用于完美轉發。在函數模板中,通過使用右值引用類型的形參來接收參數,可以實現完美轉發,即保持原參數的值類別(左值還是右值),將參數傳遞給另一個函數。
智能指針
智能指針是C++中的一種特殊指針,它是一個對象,用來管理另一個指針所指向的對象的生命周期。智能指針可以自動地分配和釋放內存,避免手動管理內存的麻煩和出錯風險。
C++標準庫提供了三種智能指針:
- shared_ptr:多個智能指針可以共享同一個對象,當最后一個指針被銷毀時,它會釋放對象的內存。
- unique_ptr:獨占式智能指針,不能共享同一個對象,當智能指針被銷毀時,它會釋放對象的內存。
- weak_ptr:弱引用智能指針,不會增加對象的引用計數,用于避免shared_ptr循環引用時的內存泄漏問題。
在哪些場景下會應用智能指針
我自己是在在動態內存管理中,使用智能指針可以避免手動管理內存的麻煩和出錯風險。
如果遇到內存泄漏這種問題,你一般是怎么去解決
打斷點定位然后做處理
后來思考對方應該是想讓我回答這種處理措施??
- 在程序中加入必要的錯誤處理代碼,避免程序因為異常情況而導致內存泄漏。
- 使用智能指針等RAII機制,自動管理內存,避免手動管理內存的麻煩和出錯風險。
- 使用內存分析工具,檢測程序中的內存泄漏,并進行相應的修復。
class中缺省的函數
沒關注
補充:
在C++中,如果一個類沒有顯式地定義「構造函數、析構函數、拷貝構造函數、賦值運算符重載函數」,那么編譯器會自動生成這些函數,這些函數被稱為缺省函數。
sort函數內部是什么
sort函數內部使用快速排序算法實現,它的時間復雜度為O(nlogn),是一種非常高效的排序算法。
快排的原理
- 選擇一個基準元素。
- 將小于等于基準元素的元素移動到數組左邊,大于基準元素的元素移動到數組右邊,這個過程稱為劃分。
- 遞歸地對劃分后的左右兩個子序列進行排序。
但是仔細想想還可以繼續回答??
在實際實現中,sort函數還有一些優化,例如:
- 當排序的元素個數小于一定閾值時,使用插入排序算法。
- 當出現大量重復元素時,使用三向劃分快速排序算法。
為什么選快排
默認它的分布是比較隨機的那種分布,然后快排在比較隨機的分布上,表現的比較好,速度比較快
多線程鎖是什么
多線程鎖是一種用來保護共享資源的機制。在多線程編程中,如果多個線程同時訪問同一個共享資源,可能會發生競態條件(Race Condition),導致程序的行為出現未定義的情況。為了避免這種情況的發生,可以使用多線程鎖來保護共享資源。
多線程鎖的基本思想是,在訪問共享資源之前先獲取鎖,訪問完成之后再釋放鎖。這樣可以保證同一時刻只有一個線程可以訪問共享資源,從而避免競態條件的發生。
常見的多線程鎖包括互斥鎖、讀寫鎖、條件變量等。其中,互斥鎖用于保護共享資源的訪問,讀寫鎖用于在讀多寫少的情況下提高并發性能,條件變量用于線程之間的同步和通信。
mysql的事務是什么
在數據庫中,事務(Transaction)是一組操作單元,這些操作單元要么全部執行成功,要么全部執行失敗。事務是保證數據庫一致性的重要機制之一,它可以將一系列的操作看作一個整體,從而保證數據庫的完整性和正確性。
事務具有四個特性,即ACID:
- 原子性(Atomicity):事務中的所有操作要么全部執行成功,要么全部執行失敗,不會出現部分執行的情況。
- 一致性(Consistency):事務執行前后數據庫的狀態是一致的,即數據庫中的約束和規則都得到了保持。
- 隔離性(Isolation):多個事務并發執行時,相互之間不會影響彼此的執行結果。
- 持久性(Durability):事務執行完成后,對數據庫所作的修改將被永久保存到數據庫中。
MySQL是一種常見的關系型數據庫,支持事務的機制。在MySQL中,事務可以
通過使用事務控制語句(Transaction Control Statements)來進行管理,包括以下三個語句:
- START TRANSACTION:開始一個事務。
- COMMIT:提交一個事務,使之生效。
- ROLLBACK:回滾一個事務,使之失效。
在MySQL中,事務默認是關閉的,需要通過設置autocommit參數為0來啟用事務。啟用事務后,可以通過執行SQL語句來進行事務操作,
TCP連接中間會有什么操作
在TCP連接中,客戶端和服務器之間會進行以下操作:
- 握手階段:客戶端向服務器發送SYN包(同步包),請求建立連接。服務器收到SYN包后,向客戶端發送SYN+ACK包(同步確認包),表示可以建立連接。客戶端收到SYN+ACK包后,再向服務器發送ACK包(確認包),表示連接建立成功。
- 數據傳輸階段:連接建立成功后,客戶端和服務器之間可以進行數據的傳輸。客戶端向服務器發送數據包,服務器接收數據包并進行處理,然后向客戶端發送響應包。客戶端收到響應包后,可以再次向服務器發送數據包,以此類推。
- 斷開連接階段:當客戶端或服務器不再需要連接時,可以發送FIN包(結束包)來請求斷開連接。對方收到FIN包后,也發送FIN包進行響應,表示同意斷開連接。當兩端都收到對方的FIN包后,連接才真正關閉。
需要注意的是,在TCP連接中可能會出現丟包、擁塞等情況,需要進行相應的處理,例如重傳丟失的數據包、調整發送窗口大小等。
算法
表內指定的區間反轉
反問
部門業務;技術棧情況
面試總結
感覺:
- 感覺還行,基本上面經都回答出來了,沒怎么具體問項目(因為我沒有好問的項目)
不足之處:
- C++的基礎知識還是不夠熟練
- 項目優化