使用方法
將滑鼠移至 "C++11特性總彙" 上面, 右方出現導航小圖示, 點選後在導航列表右上角點選固定, 再拖至左方空閒區域
該總彙編號與書中一致, 若有不明白的地方請檢視原著
<<深入理解C++11: C++11新特性解析與應用>>
預定義宏
211.預定義宏
212.
__func__
宏返回當前所在函式或結構體名字213.
#pragma once
/_Pragma(“once”)
該標頭檔案只編譯一次214.
__VA_ARGS__
變長引數宏定義#define PR(...) printf(__VA_ARGS__)
215.寬窄字串的連線
支援long long int型別
22.
long long int n
至少有64位
不同型別運算拓寬
23.
(int)a + (long long int)b
a會被提升為long long型後再進行運算
__cplusplus
宏24.用於C/C++混合編寫,
__cplusplus = 201103L
可用作檢測編譯器所支援的C++版本#ifdef __cplusplus extern "C" { #endif //some code #ifdef __cplusplus } #endif
assert
斷言
- (1) 包含在
<cassert>
的斷言assert(n > 0);
執行時若n不大於0則報錯
(2) 靜態斷言static_assert(sizeof(a) == sizeof(b), "must have same width");
編譯時報錯,不可使用變數進行靜態斷言
noexcept
關鍵詞
void func() noexcept(true);
若有異常,選擇不丟擲,而是直接終止執行並報錯,括號內常量表示式true=不丟擲, false=丟擲
花括號初始化非靜態成員
private: string name{"ABC"};
允許對非靜態成員使用sizeof
private: int n; //sizeof(class::n)可編譯透過
友元模板
29.可在模板使用友元
friend T
;
final
/override
關鍵詞
private: void func() final; //派生不可過載 void oldFunc() override; //過載必須同名,同引數,同常量性,且被過載的是虛擬函式
預設模版型別
template<typename T1, typename T2 = int> class C1; //透過 template<typename T1 = int, typename T2> class C2; //報錯,類模版預設型別需要從右往左 template<typename T1 = int, typename T2> void func(T1 a, T2 b); //透過,函式模版沒有這規定
外部模版
extern template void func<int>(int);
繼承建構函式
struct B: A{ using A::A; };
委派建構函式
class A{ public: A() : A(1234){} //先呼叫A(int) A(int n1) : A(n1, 'C'){} //先呼叫A(int, char) A(char c1) : A(2, c1){} //先呼叫A(int, char) private: A(int n2, char c2) : my_int(n2), my_char(c2){} int my_int; char my_char; }
應用於模版:
class A{ public: A(vector<int> &v) : A(v.begin(), v.end()); A(deque<short> &d) : A(d.begin(), d.end()); private: template<class T> A(A n1, T n2) : my_list(n1, n2) {} list(int) my_list; }
捕捉異常:
class A{ public: A() try : A(1234) {init();} catch(...) {error();} A(int n) {throw 0;} //構造時執行error(), 而不執行init() }
右值引用
- 331.指標成員複製構造
class A{ public: A() : my_ptr(new int(1234)) {} A(A ©) : my_ptr(new int(*copy.my_ptr)) {}//新申請一塊記憶體,避免重複析構同一塊記憶體 ~A() {delete my_ptr;} int *my_ptr; }
- 332.移動語義
class A{ public: A() : my_ptr(new int(1234)) {} A(const A& copy) : my_ptr(*copy.my_ptr) {} A(A&& move) : my_ptr(move.my_ptr) {move.my_ptr = nullptr;} ~A() {delete my_ptr;} int* my_ptr; } A GetTmp() { A tmp; return tmp; } int main(){ A one = GetTmp(); }
1.執行
GetTmp()
,建立A1並初始化後返回,
2.建立並初始化A2,即A2(A1)
, 執行的是move
而不是copy,它將A1的指標賦值給A2,並將A1的指標清掉,
3.析構A1
,由於指標清掉了,所以初始化時的記憶體沒有被釋放
4.建立並初始化one,即one(A2)
,重複第2步,第3步
5.析構one
,此時記憶體才真正被釋放,它是A1初始化時申請的
333.有名字的是左值, 沒名字的是右值, 左值
*p=1234
, 右值p=1234
334.在
<utility>
中提供了std::move
函式,它將左值強制轉化為右值引用335.
swap(T a, T b)
函式使用移動語義進行交換,
移動建構函式不應該寫丟擲異常,
編譯選項-fno-elide-constructors
關閉最佳化以使用移動/複製語義,否則變數直接替換成右值進行編譯
- 336.完美轉發
引用摺疊規則:
typedef int T; typedef T& TR; //or typedef T&& TR TR a; //or TR& a , TR&& a
TR定義為
T&
時,a的型別都是A&
TR定義為T&&
時,TR
/TR&&
的型別為A&&
,TR&
的型別為A&
template <typename T, typename U> void PF(T&& t, U& func){ func(std::forward<T>(t)); }
forward()
與move()
功能相同,完美轉發能夠把引用型別準確傳給呼叫函式
explicit
顯式轉換運算子
class A{} class B{ public: explicit operator A() const {return A();} } void func(A a){} void main(){ B b; A a1(b); //透過,直接初始化 A a2 = b; //錯誤 A a3 = static_cast<A>(b); //透過,顯式轉換 func(b); //錯誤 }
列表初始化
- 標頭檔案
<initializer_list>
,宣告一個以initialize_list<T>
模版類為引數的建構函式,就能夠使自定義類使用列表初始化void func(initializer_list<int> numbers){} int main(){ func({1, 2, 3}); func({}); }
352.使用花括號初始化可以防止型別收窄
const int x = 1234; char a = x; //透過 char b = {x}; //錯誤 char* c = new char(1234); //透過 char* d = new char{1234}; //錯誤
36.POD型別
37.聯合體
38.使用者自定義字面量
內聯名字空間
inline namespace space1{ class A{}; } namespace space2{ A a;//A in space1 class A{}; A b;//A in space2; }
模版的別名
template<typename T> using NewName = std::map<T, char*>; NewName<int> a; //等同於std::map<int, char*> a;
SFINAE規則
- 特殊場景使用特殊模板版本, 另外則是通用模板版本
struct A{ typedef int my_int; }; template <typename T> void func(typename T::my_int) {} //#1 template <typename T> void func(T) {} //#2 int main(){ func<A>(1234); //呼叫#1,因為存在 A::my_int func<int>(1234); //呼叫#2,因為不存在 int::my_int }
>>
右尖括號41.兩個右尖括號
>
在模板中不再被判定為右移, 需要右移需要加圓括號()
auto
型別推導
int a = 1; auto b = a; //b的型別為int
編譯時推導
1):auto
不能作函式形參型別
2):auto
不能對結構體中的肥靜態成員進行推導
3):auto
不能宣告陣列
4):auto
不能在例項化模板時作為模板引數
decltype
型別推導
int a = 1; decltype(a) b; //b的型別為Int uding size_t = decltype(sizeof(0)); //與using/typydef合用
編譯時推導
1):decltype
不能推導過載的函式
2):decltype
將亡值推導為右值引用
3):decltype
將左值推導為引用, 如三元運算子
,帶圓括號的左值
,++i
,arr[0]
,*ptr
4): 以上都不是,則推導為本型別
追蹤返回型別
template<typename T1, typename T@> auto Func(const T1& a, const T@& b) -> decltype(a + b){ return a + b; }
編譯時推導
基於範圍的
for
迴圈
vector<int> MyVector= {1, 2, 3, 4}; for(auto p : MyVector) { cout << p << endl; //p是解引用後的物件, 無需再*p解引用 }
條件: 迭代物件要實現
++
和==
等運算子,普通已知長度的陣列(未知長度的不行), 類要有begin
函式和end
函式
強型別列舉
enum class MyEnum: char{ e1, e2, e3}; //定義一個以char為底層實現的強型別列舉 MyEnum a = e1; //錯誤 MyEnum b = MyEnum::e1; //透過 MyEnum c = 2; //錯誤 Myenum d = MyEnum::e2; if(d > 1){} //錯誤 if((char)d > 1){} //透過
智慧指標
unique_ptr<int> up1(new int(11)); //無法被複制 unique_ptr<int> up2 = up1; //編譯錯誤, 指標唯一 unique_ptr<int> up3 = move(up1); //up1的控制權轉移給up3 up3.reset(); //顯式釋放 up1.reset(); //不會出錯
unique_ptr
只允許唯一指標指向記憶體
shared_ptr
則允許共享同一塊記憶體,它在實現上採用了引用計數,只有在計數歸零時才真正釋放記憶體
weak_ptr
不擁有控制權,其成員函式lock()
返回其指向記憶體的一個shared_ptr
物件,若其記憶體無效則返回nullptr
constexpr
常量表示式
函式:
constexpr int GetConst(){return 1;}
1): 函式體只能有單一的
return
返回語句
2): 函式必須有返回值(不能為void
)
3): 使用前必須已定義,即函式定義寫在呼叫函式前面(放至後面則出錯)
4):return
返回語句表示式中必須是一個常量表示式,且不能是執行時函式
值:
constexpr int a = 1;
它是編譯時期的值,編譯器可以選擇不為它生成資料
自定義類: 必須對建構函式加上
constexpr
關鍵詞struct MyType{ constrxpr MyType(int x): my_int(x){} int my_int; } constexpr MyType mt = {2};
1): 建構函式的函式體必須為空
2): 初始化列表只能由常量表示式來賦值
變長模板
template <typename T1, typename T2> class A{}; template <typename... SomeType> class B: private A<SomeType...>{}; B<int, char> xy;
typename
之後帶...
來說明這是一個引數包,該包名字為SomeType
構造型別B時,會呼叫B的私有基類建構函式,並進行引數包展開
即實際上執行的是A<int, char> xy
;
template <typename... B> class MyClass; template <typename A, typename... B> class MyClass<A, B...>: private MyClass<B...>{ A my_a; }; template<> class MyClass<>{};
遞迴定義,在引數個數為0時結束,從右往左
引數包可以展開的位置:
1): 表示式
2): 初始化列表
3): 基類描述列表
4): 類成員初始化列表
5): 模板引數列表
6): 通用屬性列表
7): lambda函式的捕捉列表
template <typename... A> class MyClass1: private OldClass<A...>{}; Myclass1 C1<X, Y>; //解包為 class MyClass1: private OldClass<X, Y>{}; template <typename... A> class MyClass2: private OldClass<A>...{}; Myclass2 C2<X, Y>; //解包為 class MyClass2: private OldClass<X>, private OldClass<Y>{}; template <typename... A> int GetSize(A... args){ int size = sizeof...(A); //使用sizeof...()獲取引數包的大小(個數) return size; }
原子操作
- 標頭檔案
<atomic>
,<thread>
atomic_int at1 {0}; atomic<int> at2 {0}; int Set(){ at1 = 1; at2 = 2; } int Show(){ cout << at1 << ", " << at2 << endl; //可能輸出(1,0)/(0,2)/(1,2) } int main(){ thread t1(Set, 0); thread t2(Show, 0); t1.join(); t2.join(); cout << at1 << ", " << at2 << endl; //必輸出 1, 2 }
由於編譯器的最佳化,執行時可能會打亂實際的程式碼順序
所以需要顯式使用原子類的成員函式寫入store()
和讀取load()
這些函式有2個引數,第一個是值,第二個是操作型別
操作列舉值:
memory_order_relaxed
不對執行順序作保證
memory_order_acquire
本執行緒中,所有後續的讀操作必須在本條原子操作完成後執行
memory_order_release
本執行緒中,所有之前的寫操作完成之後才能執行本條原子操作
memory_order_acq_rel
同時包含memory_order_acquire
和memory_order_release
memory_order_consume
本執行緒中,所有後續的有關本原子型別的操作,必須在本條原子操作完成後執行
memory_order_seq_cst
全部存取按照順序執行store()可用:
memory_order_relaxed
,
memory_order_release
,
memory_order_seq_cst
load()可用:
memory_order_relaxed
,
memory_order_consume
,
memory_order_acquire
,
memory_order_seq_cst
RMW(Read Modify Write)同時讀寫操作可用: 全部
thread_local
執行緒區域性變數
int thread_local tl;
quick_exit()
/at_quick_exit()
快速退出
struct A{}{ ~A(){}; } void Func(){} int main(){ A a; at_quick_exit(Func); //註冊一個函式,在quick_exit時FILO執行 quick_exit(0); //A的解構函式不執行 }
nullptr
指標空值
= default
和= delete
預設函式
class A{ public: A() = default; //使用預設建構函式, 保持POD型別 A(const A&) = delete; //刪除該函式, 且禁止過載該函式 };
lambda函式(區域性函式)
int a = 1, b = 2; auto Func1 = [=]() -> int{ return a + b; }; int c = Func1(); //c = 3 auto Func2 = [](int i1, int i2) -> int{ return i1 + i2; } int d = Func2(a, b); // d = 3
[var]
值傳遞方式捕捉變數var
[=]
值傳遞方式捕捉所有父作用域的變數,包括this
[this]
值傳遞方式捕捉當前this
[&var]
引用傳遞方式捕捉變數var
[&]
引用傳遞方式捕捉所有父作用域的變數,包括this
[&this]
引用傳遞方式捕捉當前this
資料對齊
alignas(double) int a = 1; //a按照double型別寬度對齊 alignas(alignof(double)) int b = 1; //效果相同, alignof用於獲取型別的寬度
通用屬性
Unicode
原生字串
參考資料: <<深入理解C++11: C++11新特性解析與應用>>