C++ 常見面試題匯總

基礎知識

一、C++ 基礎語法

  1. C++ 和 C 的區別?

    • C++ 支持面向對象(封裝、繼承、多態)。
    • C++ 引入模板、STL、異常處理。
  2. 值傳遞、指針傳遞、引用傳遞的區別?

    • 值傳遞:拷貝一份副本。
    • 指針傳遞:傳地址,可修改原數據。
    • 引用傳遞:別名,語法更簡潔。
  3. const 的用法?

    • 修飾變量:常量。
    • 修飾指針:const int* p(指向常量),int* const p(常指針)。
    • 修飾成員函數:void f() const; 表示函數內不能修改成員變量。
  4. static 的作用?

    • 局部靜態變量:函數調用間保持值。
    • 修飾全局變量/函數:只在文件內可見。
    • 修飾類成員:屬于類而非對象。
  5. inline 內聯函數的原理?

    • 編譯器用函數體替換調用點,減少函數調用開銷。
    • 適用于小函數,頻繁調用。

二、面向對象

  1. C++ 四大特性?

    • 封裝、繼承、多態、抽象。
  2. 多態的實現方式?

    • 靜態多態:函數重載、模板。
    • 動態多態:虛函數(虛函數表實現)。
  3. 虛函數、純虛函數、抽象類區別?

    • 虛函數:子類可重寫。
    • 純虛函數:=0,子類必須實現。
    • 抽象類:含有純虛函數,不能實例化。
  4. 虛函數表 (vtable) 的工作原理?

    • 類中有虛函數時,編譯器生成 vtable,存儲函數指針。
    • 對象包含 vptr,指向 vtable,實現動態綁定。
  5. 構造函數和析構函數的調用順序?

    • 構造:先基類,再成員對象,最后派生類。
    • 析構:先派生類,再成員對象,最后基類。

三、內存管理

  1. C++ 內存分區?

    • 棧:局部變量、函數參數。
    • 堆:new/delete 分配的內存。
    • 全局/靜態區:全局變量、靜態變量。
    • 常量區:字符串常量。
    • 代碼區:存放可執行代碼。
  2. new/delete 與 malloc/free 的區別?

    • new 調用構造函數,返回指定類型指針。
    • malloc 只分配內存,不調用構造函數。
    • delete 調用析構函數,釋放內存。
    • free 只釋放內存。
  3. 內存泄漏如何檢測?

    • 工具:Valgrind、ASan。
    • 手動:智能指針(shared_ptr, unique_ptr)。

四、C++11/14/17/20 新特性

  1. C++11 特性

    • auto 類型推導、nullptr、lambda、智能指針、右值引用、move 語義。
  2. 右值引用 & move 語義?

    • T&& 表示右值引用,用于接收臨時對象。
    • std::move 轉換為右值,避免拷貝,提高性能。
  3. 智能指針的區別?

    • unique_ptr:獨占所有權。
    • shared_ptr:引用計數共享所有權。
    • weak_ptr:弱引用,不增加計數,解決循環引用。

五、STL

  1. vector 和 list 的區別?

    • vector:連續存儲,隨機訪問快,插入刪除慢。
    • list:鏈表存儲,插入刪除快,隨機訪問慢。
  2. map 和 unordered_map 的區別?

    • map:紅黑樹實現,元素有序,O(log n)。
    • unordered_map:哈希表實現,無序,O(1) 平均。
  3. 迭代器失效問題?

    • vector 插入/刪除時可能導致迭代器失效。
    • list 插入/刪除不會影響其他迭代器。

六、多線程與并發

  1. 線程創建方式?

    • std::thread
    • std::async
    • std::packaged_task
  2. 互斥鎖和自旋鎖區別?

    • 互斥鎖:阻塞等待,適合長任務。
    • 自旋鎖:忙等待,適合短任務。
  3. 條件變量 (condition_variable) 用法?

    • 結合 unique_lock,用于線程同步。

七、設計模式

  1. 單例模式實現?

    class Singleton {
    private:Singleton() {}
    public:static Singleton& getInstance() {static Singleton instance; // C++11 保證線程安全return instance;}
    };
    
  2. 工廠模式、觀察者模式 —— 常考理論。


八、常見算法題型

  1. 二分查找模板

    int binarySearch(vector<int>& nums, int target) {int l = 0, r = nums.size() - 1;while (l <= r) {int mid = l + (r - l) / 2;if (nums[mid] == target) return mid;else if (nums[mid] < target) l = mid + 1;else r = mid - 1;}return -1;
    }
    
  2. 快速排序模板

    void quickSort(vector<int>& a, int l, int r) {if (l >= r) return;int i = l, j = r, pivot = a[l];while (i < j) {while (i < j && a[j] >= pivot) j--;while (i < j && a[i] <= pivot) i++;if (i < j) swap(a[i], a[j]);}swap(a[l], a[i]);quickSort(a, l, i-1);quickSort(a, i+1, r);
    }
    
  3. LRU 緩存(哈希表 + 雙鏈表)

    • 高頻考點,需熟練掌握。

九、綜合類問題

  1. C++ 內存對齊規則?
  2. 深拷貝 vs 淺拷貝區別?
  3. 智能指針的循環引用問題怎么解決?
  4. 多態中析構函數為什么要設為虛函數?

高級知識點

一、 對象生存期與資源管理(RAII / Rule of Five)

  • RAII:資源由對象構造獲取(constructor),析構釋放(destructor)。推薦把資源封裝在對象里,避免裸 new/delete。
  • Rule of Five:如果定義了自定義析構、拷貝/賦值/移動中的任意一個,通常要考慮五個函數:~T()T(const T&)T& operator=(const T&)T(T&&) noexceptT& operator=(T&&) noexcept
  • noexcept:移動構造/移動賦值應盡量標注 noexcept,因為很多 STL 容器在需要判斷是否可用 noexcept move 時會選擇拷貝或移動;若移動不是 noexcept,容器在擴容等操作時可能退回到拷貝(性能或語義影響)。

示例(拷貝-移動-釋放的正確實現):

class Buffer {size_t n_;int* data_;
public:Buffer(size_t n=0): n_(n), data_(n ? new int[n]() : nullptr) {}~Buffer(){ delete[] data_; }// copyBuffer(const Buffer& o): n_(o.n_), data_(o.n_ ? new int[o.n_] : nullptr) {std::copy(o.data_, o.data_ + n_, data_);}Buffer& operator=(Buffer o){ // copy-and-swap 提供強異常安全swap(*this, o);return *this;}// moveBuffer(Buffer&& o) noexcept : n_(o.n_), data_(o.data_) {o.n_ = 0; o.data_ = nullptr;}Buffer& operator=(Buffer&& o) noexcept {if (this != &o) {delete[] data_;n_ = o.n_; data_ = o.data_;o.n_ = 0; o.data_ = nullptr;}return *this;}friend void swap(Buffer& a, Buffer& b) noexcept {using std::swap;swap(a.n_, b.n_);swap(a.data_, b.data_);}
};

面試點:為什么 operator=(Buffer o)(按值)提供強異常安全?因為拷貝發生在進入函數時,隨后 swap 保證不會拋異常;若拷貝失敗,原對象不受影響。


二、拷貝 vs 移動 vs 完美轉發

  • std::move:將左值轉換為右值(允許“移動”語義)。它只是類型轉換,不做實際移動。
  • std::forward<T>:用于完美轉發(保持值類別),常出現在模板轉發場景(T&& 是 forwarding reference)。
  • 完美轉發示例(容器 emplace 風格):
template<typename T>
void push_back_emplace(std::vector<T>& v, T&& val) {v.emplace_back(std::forward<T>(val)); // 保持傳入值類別
}

面試點:區分 forwarding reference(模板 T&&)和純右值引用。


三、 異常安全分級(面試必問)

  • 無保證(No guarantee):函數失敗后程序狀態不確定。
  • 基本保證(Basic):不泄露資源,對象處于有效但未定義的狀態。
  • 強保證(Strong):要么成功,要么回滾到原狀態(事務式)。
  • 不拋異常保證(No-throw):函數保證不拋異常(對析構函數很重要)。

實現強保證常用技術:copy-and-swap、先構造新對象再替換。


四、 Undefined Behavior(UB)——必須會舉例并解釋

常見 UB:

  • 訪問釋放后的內存(use-after-free)。
  • 雙重釋放(double free)。
  • 有符號整數溢出(int 溢出是 UB)。
  • 解引用空指針。
  • 同時無同步的并發讀寫(data race)。
    示例:
int a = INT_MAX;
int b = a + 1; // 有符號溢出 —— UB(不要假設會 wrap-around)

面試點:說明 UB 會讓編譯器基于假設做優化,從而產生難以預期的行為。


五、STL 深入(常被問到的細節)

  • push_back vs emplace_backemplace_back 直接在容器末構造對象(避免一次臨時拷貝/移動)。

  • reserve:對 vector 預分配容量以避免多次 realloc(均攤復雜度)。

  • 容器復雜度與迭代器失效規則(面試常問)。舉例:

    • vector:reallocation(如 push_back 導致容量增長)會使所有指針/引用/迭代器失效;在中間 insert/erase 會使其后的迭代器失效。
    • list / forward_list:插入/刪除不影響除被刪除元素外的迭代器(穩定迭代器)。
    • map(平衡樹):插入/刪除不會使其他元素的引用/迭代器失效(除了被刪除的)。
    • unordered_maprehash 會使迭代器失效;插入可能導致 rehash。
  • allocator 基本概念:定制內存分配策略(進階題)。

面試點:能解釋為什么對 vector resize 可能觸發移動還是拷貝(取決于元素是否可 noexcept move)。


六、 并發與內存模型(非常重要)

  • 數據競爭(Data race):兩個或多個線程無同步地訪問同一內存位置,且至少一個為寫,程序行為未定義。
  • std::mutex / std::lock_guard / std::unique_lock:RAII 鎖封裝;std::scoped_lock 用于多鎖防死鎖。
  • std::atomic<T>:提供原子操作和內存序(memory_order_relaxed/acquire/release/seq_cst)。
  • compare_exchange_weak vs compare_exchange_strong:weak 可能虛假失敗(適用于循環),strong 不會。
  • ABA 問題:CAS 僅比較值,若中間值先改為 B 再改回 A 會誤判。常用解決:加版本號(tagged pointer)、使用 hazard pointers 或垃圾回收策略。
  • 線程同步經典題:std::condition_variable 的使用(生產者-消費者),std::call_oncestd::once_flag 做線程安全單例。

示例(線程安全單例,C++11 更簡單):

MySingleton& instance() {static MySingleton inst; // C++11 保證線程安全的局部靜態初始化return inst;
}

示例(簡單生產者-消費者):

std::mutex mu;
std::condition_variable cv;
std::queue<int> q;void producer() {{std::lock_guard lk(mu);q.push(42);}cv.notify_one();
}void consumer() {std::unique_lock lk(mu);cv.wait(lk, []{ return !q.empty(); });int v = q.front(); q.pop();
}

七、 性能與優化實踐(面試考點)

  • CPU 緩存友好(contiguous memory 優于鏈表),盡量讓熱點數據放在一起。
  • 減少內存分配(使用內存池 / reserve)。
  • 避免不必要的拷貝(move semantics、emplace)。
  • 關注分支預測、內聯(inline)與編譯器優化,先用 profiling(perf / gprof)確認熱點,再優化。
  • 提前測量:microbenchmark(防止過早優化)。

八、 常見進階題與樣例實現(面試常問,附模板)

a) LRU Cache(O(1) get/put)

class LRUCache {int cap;list<int> keys;unordered_map<int, pair<int, list<int>::iterator>> mp;
public:LRUCache(int capacity): cap(capacity) {}int get(int k) {auto it = mp.find(k);if (it == mp.end()) return -1;keys.splice(keys.begin(), keys, it->second.second);return it->second.first;}void put(int k, int v) {auto it = mp.find(k);if (it != mp.end()) {it->second.first = v;keys.splice(keys.begin(), keys, it->second.second);return;}if ((int)mp.size() == cap) {int old = keys.back();keys.pop_back();mp.erase(old);}keys.push_front(k);mp[k] = {v, keys.begin()};}
};

面試點:解釋 splice 的常數復雜度和為什么使用 list + unordered_map

b) 線程安全單例(call_once

class S {
public:static S& instance() {static std::once_flag f;static S* p = nullptr;std::call_once(f, []{ p = new S(); });return *p;}
private:S() = default;
};

c) Copy-swap 異常安全賦值

(見 Buffer 示例)


九、 調試與檢測工具(面試可能問會用哪些)

  • AddressSanitizer (ASan):檢測內存越界、use-after-free。
  • UndefinedBehaviorSanitizer (UBSan):檢測 UB(如有符號溢出)。
  • ThreadSanitizer (TSan):檢測 data race。
  • Valgrind:檢測內存泄漏(Linux)。
  • gdb / lldb:調試斷點、查看 backtrace。
  • perf / Flamegraphs:性能分析。

十、 高頻面試問題(附要點回答)

  • 為什么要用 unique_ptr 而不是裸指針?
    → 表達所有權,自動釋放,防止泄漏;shared_ptr 代價(引用計數)比 unique_ptr 高,且會引入循環引用風險。
  • std::move 之后對象狀態如何?
    → 留在“可析構但未指定狀態”,只能賦值或析構;使用前須重新賦值或立即處理。
  • volatile 在 C++ 中的作用?
    → 不用于線程同步;僅抑制某些編譯器優化,真正并發應使用 std::atomic
  • 如何避免死鎖?
    → 統一鎖順序、使用 std::scoped_lock、用 try_lock 超時退讓、減少鎖粒度。
  • 如何寫高性能 IO / 內存敏感代碼?
    → 減少 system call、使用緩沖、減少分配、考慮內存對齊/預取/向量化。

小建議

  • 練習方式:讀題后寫出 O(1)/O(n) 解法,然后討論邊界、異常安全、并發假設與性能瓶頸。
  • 面試時不要只寫能過的代碼,還要能解釋時間/空間復雜度、是否有 UB、異常安全級別、并發安全假設與潛在改進。

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

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

相關文章

ES06-SpringData集成

ES06-SpringData集成 文章目錄ES06-SpringData集成1-參考網址2-知識整理3-Spring Data Elasticsearch 9.0.0 完整示例4-知識補充1-Elasticsearch JAVA操作有三種客戶端:1. TransportClient&#xff08;已廢棄&#xff09;2. JestClient&#xff08;第三方 HTTP 客戶端&#xff…

對于鏈表相關經典算法題:環形鏈表的約瑟夫問題的解析

開篇介紹&#xff1a; Hello 大家&#xff0c;在上一篇博客中&#xff0c;我們一同拆解了「206. 反轉鏈表」和「876. 鏈表的中間結點」這兩道單鏈表經典題目&#xff0c;通過對指針操作的細致打磨&#xff0c;相信大家對單鏈表的特性與算法設計思路有了更深入的理解。而在今天…

MySQL集群——主從復制

目錄 一、環境搭建、部署 1. RHEL7.9、9.3的搭建 二、主從復制 1. 環境說明 2. 環境準備 1&#xff09;克隆RHEL79_mysql_master 2&#xff09;改名為 “RHEL79_mysql_slave” 并修改IP 3&#xff09;修改主機名 3. 部署MySQL主從同步 1&#xff09;主庫(mysql-master) 2&…

《用 asyncio 構建異步任務隊列:Python 并發編程的實戰與思考》

《用 asyncio 構建異步任務隊列:Python 并發編程的實戰與思考》 一、引言:并發編程的新時代 在現代軟件開發中,性能已不再是錦上添花,而是產品成功的基石。尤其在 I/O 密集型場景中,如網絡爬蟲、實時數據處理、微服務通信等,傳統的同步編程模式往往力不從心。 Python …

【Linux】yum工具篇

目錄一、軟件包管理器1.1 什么是軟件包1.2 Linux軟件生態二、yum具體操作2.1 查找軟件包2.2 安裝軟件包2.3 卸載軟件配置文件所在路徑個人主頁<—請點擊 Linux專欄<—請點擊 一、軟件包管理器 1.1 什么是軟件包 在Linux下安裝軟件, 一個通常的辦法是下載到程序的源代碼…

撬動制造全場景增效,開利空調找到了怎樣的“通關密碼”?

由深圳軟件協會指導、法大大和信息俠聯合出品的《制造行業合同數智化升級白皮書》&#xff08;以下簡稱“白皮書”&#xff09;首次提出了 “電子簽法律AI” 雙輪驅動模型。在制造行業面臨供應鏈協同、合規風控及全球化出海等多重挑戰的當下&#xff0c;法大大依托豐富的制造企…

[Android]RecycleView的item用法

RecyclerView 是 Android 提供的一個強大的列表控件&#xff0c;用來顯示大量數據。RecyclerView 的主要特點 1. 高性能的視圖復用機制 Recycle就是循環的意思&#xff0c;那么recycleview的特點也很鮮明了&#xff0c;它只會創建出在屏幕內和一定緩存的itemview,當view滑出屏幕…

AI驅動的軟件測試:革命性的自動化、缺陷檢測與實驗優化

引言在當今快節奏的軟件開發生命周期&#xff08;SDLC&#xff09;中&#xff0c;傳統測試方法已逐漸無法滿足對速度、覆蓋面和準確性的極高要求。人工智能&#xff08;AI&#xff09;和機器學習&#xff08;ML&#xff09;技術的融入&#xff0c;正在從根本上重塑軟件測試的格…

繼續優化基于樹狀數組的cuda前綴和

在之前的博客《借助樹狀數組的思想實現cuda版前綴和》中&#xff0c;我們用三個kernel實現了基于樹狀數組的cuda版前綴和&#xff0c;但是在數據量較大時速度不如傳統的reduce-then-scan方法&#xff0c;主要原因在于跨block的reduce階段沒有充分利用所有的cuda核心。在本博客中…

Qt圖片資源導入

右鍵項目&#xff0c;點擊添加新文件 選擇Qt -> Qt Resource File 資源文件起名 如&#xff1a;res 生成res.qrc文件 在項目的同級目錄下創建文件夾res&#xff0c;并將準備好的資源粘貼進去 右鍵qrc文件&#xff0c;選中Open in Editor 添加前綴 前綴是各種類型圖片的分類&…

嵌入式第四十六天(51單片機(中斷,定時器))

一.獨立按鍵設置1.#include "key.h"void init_key(void) {P1 | (0x0F << 4); }int key_pressed(void) {static int ret 0;if((P1 & (1 << 4)) 0){ret 1;}else if((P1 & (1 << 5)) 0){ret 2;}else if((P1 & (1 << 6)) 0){r…

Visual Studio Code2024安裝包及安裝教程

一、軟件下載軟件名稱&#xff1a;Visual Studio Code 2024安裝環境&#xff1a;window10及以上系統下載鏈接&#xff1a;https://pan.quark.cn/s/d9831b28c69a解壓軟件Bandizip下載鏈接&#xff1a;https://pan.quark.cn/s/a54e79b5d553二、軟件安裝1、下載后&#xff0c;先解…

fps:游戲玩法

能幫到你的話&#xff0c;就給個贊吧 &#x1f618; 文章目錄游戲玩法倒計時僵尸潮游戲成功&失敗計時玩法&#xff1a;玩家在計時內存活&#xff0c;成功&#xff1b;反之失敗Game界面&#xff1a;由關卡調用計時系統計時完成&#xff1a;調用結果界面結果界面玩家死亡&…

如何建立針對 .NET Core web 程序的線程池的長期監控

如何建立針對 .NET Core web 程序的線程池的長期監控 建立針對 .NET Core Web 應用程序線程池的長期監控是一個系統性的工程&#xff0c;它涉及代碼集成、指標收集、存儲、可視化和告警。 核心思路 線程池監控不是孤立的&#xff0c;它必須與應用程序的整體性能指標&#xff08…

前端開發學習路徑

前端開發學習路徑前端開發基礎技能HTML、CSS和JavaScript是前端開發的三大核心技術。HTML用于構建網頁結構&#xff0c;CSS負責樣式設計&#xff0c;JavaScript實現交互功能。掌握這三項技術是學習前端開發的基礎。現代前端開發通常需要了解ES6語法&#xff0c;包括箭頭函數、解…

一款沒有任何限制的免費遠程手機控制手機的軟件簡介

這是一款沒有任何限制的免費遠程手機控制手機的軟件支持安卓和蘋果1.安裝1.1被控制端安裝airdroid1.2控制端air mirror2.登錄同一個賬號3.控制使用打開控制端軟件選擇要控制的機器直接點“遠程控制“連接上后就可以任意操作被控手機了

在word中使用lateX公式的方法

非常好的問題&#xff01;這是一個許多科研人員和學生都渴望實現的功能。但需要明確的是&#xff1a; **Microsoft Word 本身并不具備“自動”將 LaTeX 代碼實時轉換為渲染后公式的功能。** 它不像 Overleaf 或 VS Code 的 Markdown 插件那樣&#xff0c;輸入 $Emc^2$ 就立刻變…

23種設計模式——代理模式(Proxy Pattern)詳解

?作者簡介&#xff1a;大家好&#xff0c;我是 Meteors., 向往著更加簡潔高效的代碼寫法與編程方式&#xff0c;持續分享Java技術內容。 &#x1f34e;個人主頁&#xff1a;Meteors.的博客 &#x1f49e;當前專欄&#xff1a;設計模式 ?特色專欄&#xff1a;知識分享 &#x…

webpack scope hositing 和tree shaking

Scope Hoisting&#xff08;作用域提升&#xff09; 和 Tree Shaking&#xff08;搖樹優化&#xff09; 是現代前端構建中至關重要的概念。它們是構建工具&#xff08;如 Webpack、Rollup、Vite&#xff09;用來優化最終打包產物的核心技術。 核心概念快速理解 Tree Shaking&am…

手寫React狀態hook

在日常開發中&#xff0c;我們經常用到 React 的狀態管理 Hook&#xff1a;useState 和 useReducer。 但你有沒有想過&#xff1a;這些 Hook 內部是怎么實現的&#xff1f;為什么調用 setState 之后組件會重新渲染&#xff1f; 今天我們就來從零手寫 useState 和 useReducer&am…