首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ Primer 學習筆記(二):作用域、指針、內存模型與 STL 算法

     編輯:關於C++

八、作用域與生命週期

名字空間作用域

不包含在函數聲明、定義或類定義內的程式文本屬於名字空間作用域(全域作用域)。程式設計師可透過 namespace 定義用戶自訂名字空間,它們嵌套在全域作用域中。

名字查找規則

局部作用域的名字解析遵循「由內而外」原則:先在使用該名字的作用域查找,找不到則往外層作用域繼續,直到全域作用域;若仍未找到則報錯。

單一定義規則 (ODR)

全域對象與函數在一個程式中只能有一個定義,或有多個完全相同的定義。

全域對象初始化

未顯式初始化的全域對象會被零初始化。extern 關鍵字用於聲明而非定義對象,承諾該對象在別處定義。

頭文件規範

  • 頭文件不應包含非 inline 函數或對象的定義(如 extern int ival = 10; 會導致多重定義)。
  • 符號常量與 inline 函數可在多文件中重複定義,前提是定義對使用點可見。
  • 大型項目可使用預編譯頭文件減少編譯時間。

指針與 const 綜述

類型宣告形式含義
常量指針const int* p / int const* p指向的值不可透過該指針修改
指針常量int* const p指針本身(地址)不可修改,指向的值可改
指向常量的常指針const int* const p指針與指向的值均不可修改

內聯函數與自動對象

  • inline 用於消除函數調用開銷,適用於小型、高頻函數;編譯器可自行決定是否內聯。
  • 自動對象的存儲分配發生在函數調用時,函數結束時釋放;切勿返回自動對象的地址,否則會產生懸空指針。
  • 頻繁使用的自動變量可用 register 建議編譯器放入寄存器(現代編譯器通常自動優化,register 關鍵字已弱化)。

動態內存管理

new / delete 表達式

  • new 返回指向動態分配對象的指針,內存未初始化(除非使用 new int(0) 等初始化語法)。
  • 分配失敗拋出 std::bad_alloc 異常。
  • delete 釋放內存,指針本身不變,成為「懸空指針」;良好習慣是 ptr = nullptr;。

智能指針 auto_ptr(C++98,C++11 棄用,建議用 unique_ptr/shared_ptr)

  • 擁有權語義:複製或賦值會轉移擁有權,右值變為空指針。
  • 生命週期結束時自動 delete 管理的對象。
  • 常用操作:get() 取原始指針、reset() 重置/釋放舊對象並接管新對象、release() 釋放擁有權並返回原始指針。
  • 嚴禁 用非 new 分配的指針初始化 auto_ptr。

動態數組

new Type[N] 分配數組,delete[] ptr 釋放。只有第一維可用運行時變量指定大小,其餘維度必須為編譯期常量。

名字空間進階

  • 未命名名字空間:namespace { ... } 內部名字僅在本翻譯單元可見,可替代 static 全域變量/函數。
  • 跨文件名字空間:同一名字空間可跨多個頭文件/源文件定義。
  • 名字空間別名:namespace IBM = International_Business_Machines;
  • using 聲明/指示:using ns::name; 引入單一名字;using namespace ns; 將整個名字空間名字引入當前作用域。

static 關鍵字

  • 靜態局部變量:存儲在靜態存儲區,生命週期贯穿整個程式,作用域僅限函數內;首次調用初始化,後續調用保持上次值。
  • 靜態全域變量:內部鏈接,僅在定義文件可見,生命週期為程式整個運行期;未初始化自動歸零。

九、函數重載

  • 重載判斷依據:參數列表(個數、類型、順序)不同;返回類型不參與重載區分。
  • const/volatile 修飾頂層參數類型時不影響重載區分;但修飾指針/引用指向的類型則影響(如 int* vs const int*)。
  • using 聲明不可指定參數列表;using namespace 使名字空間成員如同在外部聲明。
  • 指向重載函數的指針:通過函數指針類型匹配決定綁定哪個重載版本。

重載決議:最佳匹配

  1. 候選函數 → 可行函數(參數數量匹配或有默認實參) → 最佳匹配。
  2. 轉換等級:精確匹配 > 提升 > 標準轉換 > 用戶定義轉換。
  3. 五種標準轉換(整型、浮點、浮點↔整型、指針、bool)等級相同;若兩個可行函數都需標準轉換則構成二義性錯誤。

十、函數模板

模板提供一套演算法,編譯器根據實參類型自動具現化具體函數,保留強類型檢查與語義,避免巨集的副作用。

template 
T min(T a, T b) { return a < b ? a : b; }

// 非類型模板參數
template 
T min(T (&arr)[Size]);

十一、異常處理

  • throw 可拋出任意類型對象,通常用類封裝異常信息。
  • try 塊包圍可能拋出異常的代碼,後接一組 catch 子句處理特定類型異常。
  • 異常拋出後,後續語句跳過,執行權轉交匹配的 catch;若無匹配則調用 std::terminate()(預設 abort())。
  • 堆疊展開:尋找處理器過程中退出的複合語句與函數會銷毀其中的自動對象。
  • 重新拋出:catch (...) { throw; } 或修改異常對象後 throw;(需以引用捕獲)。
  • main() 中聲明的變量不可在 catch 子句中直接引用。

十二、泛型算法與迭代器

核心概念

  • 算法:操作容器元素的函數模板,多數定義於 <algorithm>,透過迭代器存取元素,不依賴具體容器類型。
  • 迭代器:泛化指針,支援 ++、--、解引用、比較等操作;分為五類:
    • InputIterator(只讀單向)
    • OutputIterator(只寫單向)
    • ForwardIterator(讀寫單向)
    • BidirectionalIterator(雙向)
    • RandomAccessIterator(隨機存取,支援 +n、-n、[]、比較)
  • 容器對應迭代器類別:vector/deque → 隨機存取;list/set/map → 雙向;stack/queue/priority_queue → 不支援迭代器。

常用算法示例

// find:在 [first, last) 尋找 val,找到返回迭代器,否則返回 last
template 
InIt find(InIt first, InIt last, const T& val);

// sort:預設用 operator<,可傳入比較函數對象(如 greater<> 以降序排列)
sort(vec.begin(), vec.end(), greater());

// 二分查找要求區間有序
lower_bound(first, last, val); // 首個 >= val
upper_bound(first, last, val); // 首個 > val
equal_range(first, last, val); // 返回 pair 等於 val 的區間

// 排列組合
next_permutation(first, last); // 字典序下一個排列
prev_permutation(first, last); // 字典序上一個排列

算術算法

adjacent_difference、accumulate、inner_product、partial_sum(需 <numeric>)。

預定義函數對象

定義於 <functional>,分算術、關係、邏輯三類,皆為類模板,如 plus<T>、less<T>、logical_and<T>。

const 容器與迭代器

const 容器只能綁定 const_iterator,確保元素不可被修改,類比 const 指針指向 const 對象。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved