## 前言 函數是C語言中的基本構建塊之一,它允許我們將代碼組織成可重用、模塊化的單元。 本文將逐步介紹C語言函數的基礎概念、參數傳遞、返回值、遞歸以及內聯函數和匿名函數。 ## 一、人物簡介 - 第一位閃亮登場,有請今後會一直教我們C語言的老師 —— 自在。 ![](https://img2023 ...
C++標準
1. C++標準簡介
The document specifies requirements for implementations of the C++ programming language.
美國國家標準局(American National Standards Institute, ANSI) 在1990年設立了一個委員會(ANSI X3J16),專門負責制定C++標準(ANSI制定了C 語言標準)。國際標準化組織(the International Organization for Standardization, ISO) 很快通過自己的委員會(ISO-MG-21) 加入了這個行列,創建了聯合組織 ANSI/ISO,致力於制定C+標準。
第一版,國際標準 ISO/IEC 14882:1998,於 1998 年獲得 ISO、IEC(the International Electrotechnical Commission, 國際電工技術委員會) 和ANSI的批准。該標準常被稱為C++98,它不僅描述了已有的 C++特性,還擴展了C++、添加了異常、運行階段類型識別(RTTI)、模板和標準模板庫(STL)。
第二版,ISO/IEC 14882:2003,對C++98的技術性修訂,主要修訂錯誤,減少多義性,沒有改變語言特性,該版本稱為C++03.
第三版,ISO/IEC 14882:2011,2011年9月11日正式發佈,增加了許多新的語言特性。該版本稱為C++11,還曾被稱為C++ 0x,x曾預期為7或8.
第四版,ISO/IEC 14882:2014,在11基礎上進行細微的完善和改進,該版本稱為C++14. 包括:允許二進位字面量int var = 0b110;
'0b'或 '0B'開頭,但只能用來表示整型。
第五版,ISO/IEC 14882:2017,增加了一些特性,如允許命名空間嵌套定義,用新語法來定義函數的異常規格,引入新語法-推斷指引(Deduction Guildes)等。該版本稱為C++17.
第六版,ISO/IEC 14882:2020,2020年12月發佈。官方文檔ISO/IEC 14882:2020(en), Programming languages — C++.
第七版,ISO/IEC DIS 14882,正在開發中。ISO官網 https://www.iso.org/standard/83626.html
2. C++11新特性
-
統一的列表初始化方式。擴大了列表初始化的適用範圍,使其可用於所有內置類型和用戶定義的類型(類的對象)。並且,使用初始化列表時,可添加等號”=”,也不省略。
int x1 = {5}; int x2 {55}; short nums[3] {1,2,3};
列表初始化禁止縮窄變換,即一個較大的數放進一個較小類型的變數里,但允許較窄類型的數放進較寬類型的變數里。
類對象也可使用列表初始化。若類的某個構造函數接收模板類initializer_list作為函數的參數,則初始化列表語法只能用於該構造函數。
-
關鍵字聲明
auto以前是一個存儲類型說明符,動態存儲,C++11將其用於自動類型推斷,必須進行顯式初始化。
decltype根據表達式類型定義變數類型。在使用模板函數時很方便,推導變數類型。
decltype(x*n) y; // y的類型是x*n表達式的類型。
-
函數的返回類型後置
double f1(double, int); auto f1(double, int) –> double;
-
此前,typedef可用於給數據類型起別名,現增加一種創建別名的語法 using = :
using itType = vector<string>:: iterator;
using 還可用於給模板類起別名,如vector、array等。
-
nullptr空指針
空指針是不會指向有效數據的指針。此前,使用0來表示該指針,但和整型的0衝突。C++11新增nullptr表示空指針,是指針類型,不可轉換為整型。仍允許使用0來表示空指針,為向後相容,因此nullptr==0 為true。
-
智能指針
new的記憶體需要程式員顯式delete釋放,舊版本提供auto_ptr來自動完成該過程,但C++11廢棄auto_ptr,新增3種智能指針unique_ptr,shared_ptr,weak_ptr。
auto_ptr,unique_ptr,shared_ptr相當於對象,當指針的生命周期到時時,(在局部函數里,函數調用結束,棧釋放,auto_ptr等自然不復存在),指針的析構函數將使用delete來釋放所指向的記憶體空間。
auto_ptr<int> pt (new int);
需
#include <memory>
,智能指針模板位於名稱空間std中。智能指針定義時當作對象,使用時當作普通指針即可。由於智能指針會自動釋放堆記憶體,要嚴格註意指針間賦值操作。但普通指針不需要有這種困擾。
unique_ptr採用所有權模型,在一個作用域內,只能有一個指針指向同一塊堆記憶體,unique_ptr在編譯期檢錯;auto_ptr採用所有權模型,在運行期檢錯;shared_ptr,採用引用計數,允許多個指針指向同一塊堆記憶體。
-
作用域內的枚舉enum
以前,同一作用域中不同枚舉類型的成員不能重名。由於不同的實現可以選擇不同的底層類型,因此枚舉可能不能完全移植。C++新增枚舉聲明,添加class或struct定義。
enum class color {red, yellow, blue};
引用特定枚舉值需要顯式使用限定符,如New1::never, New2::never.
-
類
C++11允許類定義里初始化成員變數,但構造函數里對成員變數的修改會覆蓋初始化的值。
構造函數被繼承和彼此調用
管理虛方法virtual:以前,如果子類的同名函數
-
右值引用
傳統的引用可關聯左值,左值可出現在賦值語句的左邊,可獲取地址。但const常量可獲取地址,但不能賦值。
const int b = 0; const int & rb = b; // 引用前必須也加const
C++11新增右值引用,用&&表示,右值是可以出現在”=”右邊,但不能對其應用地址運算符的值,包括字面常量(C風格字元串除外,它表示地址)、表達式、返回類型為數值類型的函數。
int && rt = 13; // 相當於int rt = 13; rt可以獲取地址。改變值。
引入右值引用的主要目的是實現移動語義。
-
移動語義允許將1個對象的資源所有權從自己轉移到另一個對象,而不需進行昂貴的複製操作。
std::move()
,如unique_ptr智能指針。拷貝構造函數:創建新對象,分配記憶體和複製數據
移動構造函數:使用右值引用來接收1個臨時對象或1個即將被銷毀的對象,將其資源所有權轉移到新對象中。只涉及指針的複製。
-
模板類和標準模板庫(STL, Standard Templates Library)
C++11新增STL容器unordered_map, unordered_multimap, unordered_set, unordered_multiset, forward_list(單向鏈表,對比於雙向鏈表list)。前4種使用哈希表實現。新增模板array(就是個數組array<int, 5>,定義之後長度不可變,因此沒有push_back等方法)。
對於內置數組,含有方法begin(), end()的類,如string,和STL容器,可使用
for(auto/type x: container)
迴圈,若要修改x的值,則使用引用for(auto/type &x: container)
。新增cbegin(), cend(),是begin(), end()的const版本,防止對原容器的元素進行誤改等操作。
begin(), end(), 分別指向容器的第一個元素,容器最後一個元素的後面。rbegin(), rend(), 分別指向容器的最後一個元素,容器第一個元素的前面,聯合使用達到逆序遍歷的效果。crbegin(), crend()是其const版本。
舊版使用嵌套模板時,尖括弧要用空格分開,防止與運算符”>>”混淆,
vector<list<int> > vec;
C++11不再要求,
vector<list<int>> vec;
-
多線程
新增 線程支持庫<thread>, <mutex>, <condition_variable>和<future>
新增 原子操作庫
關鍵字thread_local,靜態存儲,與每個線程綁定一個,持續性和綁定的線程一致。
-
Lambda表達式/Lambda函數
lambda函數也叫lambda表達式,就是匿名函數。C++11中,對於接收函數指針或函數符(STL中函數對象)作為參數的函數,可以使用lambda作為參數。
lambda表達式定義的地方和調用的地方在同一個地方,便於調試和修改代碼。通常lambda沒有名字,也可給lambda指定名稱。
auto func = [] (int x) {return x % 3 == 0;}; // 給lambda指定名稱func bool res = func(3);
當lambda函數體只有一條語句時,如只有一條return,可不顯式寫返回類型,由decltype推斷。否則,需要顯式寫返回類型,採用返回類型後置的格式,如下:
[] (int x) –> int {x = 1; return x % 3;};
lambda捕獲方式主要有三種:值捕獲、引用捕獲和隱式捕獲,使lambda函數體內可使用外部所有動態變數。有兩種方式傳入外部變數,一種是引用&,一種是值=,如果只傳特定變數(顯式捕獲),則傳值方式時可省略=(值捕獲),傳引用方式不可省略&(引用捕獲)。傳全部的外部變數時(隱式捕獲),值方式用“=”標識所有變數,引用方式用“&”。捕獲的變數放進 [] 里聲明。
[m,&n] (int x) –> int {x = m; return x % 3;}; // 值捕獲:m傳值,引用捕獲:n傳引用 [=] (int x) –> int {x = n; return x % 3;}; // 隱式捕獲:外部所有變數都通過值方式傳遞 [&] (int x) –> int {x = n; return x % 3;}; // 隱式捕獲:外部所有變數都通過引用方式傳遞 [=,&n] (int x) –> int {x = n; return x % 3;}; // 表示n以引用方式傳遞,剩餘變數以值方式傳遞 // 隱式捕獲與顯式捕獲混用時,隱式捕獲必須是[]里第一個參數
一些註意事項和詳細例子:C++ lambda表達式詳細講解2-隱式捕獲與顯式捕獲-bingma03的博客-CSDN博客