《深入理解C++11》要點總結


3.1 繼承構造函數
     通過using關鍵字可以繼承父類的構造函數。也可以通過顯式定義構造函數來阻止繼承。
3.2 委派構造函數,減少構造函數的書寫
class Info {
public:
    Info() { InitReset(); }
    Info(int i) : Info() { type = i; }  //通過調用無參構造函數,可以減少構造函數內容的重寫
    Info(char e) : Info() { name = e; }  //委派構造函數和初始化列表不能同時存在,使用委派構造函數后,初始化代碼需要放在函數體中
 
private:
    int type { 1 };         //初始化成員變量
    char name { 'a' };
 
    void InitReset() {}
};
3.3.2 移動語意學
     通過移動構造函數可以減少臨時對象中的數據拷貝。
3.3.3 左值、右值和右值引用
     有名字的可以取地址的是左值(&a),沒有名字,不能取地址的是右值( &(b+c)是錯誤操作 ),所以a是左值,(b+c)是右值
     T && a = ReturnRvalue(); //獲得一個右值引用,只有在a的生命周期中,函數返回的右值持續存活
     右值引用不能綁定左值,如 int c; int && d = c;  //錯誤
     可以通過<type_traits>中的模板類來判斷值的類型,如 is_rvalue_reference<string &&>::value;
3.3.4 std::move 將一個左值強制轉化為右值引用,從而可以通過右值引用使用該值
     如果聲明了移動構造函數、移動賦值函數、拷貝賦值函數和析構函數中的一個或多個,編譯器不會再生成默認的拷貝構造函數。所以拷貝構造/賦值和移動構造/賦值函數必須同時提供或者都不提供。
3.5 列表初始化
     等號加上賦值表達式,如 int a = 3 + 4;
     等號加上花括號,如 int a = {3+4};
     圓括號式的表達式 ,如 int a (3+4);    可以用於堆內存的new操作,如 int *i = new int(1);
     花括號式的表達式,如int a {3+4};     double *d = new double{2.3f};
 
     使用列表初始化,在出現類型收窄時會編譯失敗,如 char c = {1024}; //無法通過編譯
3.8 字面量操作符  ret operator “” _x(arguments) {} 可以定義字面量操作符
struct Watt {
    unsigned int v;
};
 
Watt operator "" _w(unsigned long long v)
{
    return { (unsigned int)v };
}
     如果字面量為整型數,那么字面量操作符函數只可以接受unsinged long long或const char*為參數
     如果字面量為浮點型數,函數只可接受long double或const char*為參數
     如果字面量為字符串,函數只接受const char*, size_t為參數
     如果字面量為字符,函數只可以接受一個char為參數
 
4.2 auto 自動類型推導
     使用auto聲明的變量必須被初始化,從而使編譯器能夠從初始化表達式中推導出其類型
     auto可以用於new關鍵字,auto z = new auto(1);
     auto不能用作形參的類型,即使提供了默認參數,如  void fun(auto x = 1) {} //編譯失敗
     auto也不能用於結構體的非靜態成員變量,即使成員擁有初始值,如 struct str { auto var = 10; } //編譯失敗
     不能聲明auto數組
     在實例化模板的時候不能使用auto作為模板參數,如 vecotr<auto> v = {1};  //編譯失敗
4.3 decltype可以用於獲取對象類型,獲取的類型可以用於定義對象,如 vector<int> vec; typedef decltype(vec.beging()) vectype;
     decltype只接受表達式作為參數(如,decltype( Func(x)),而不接受 decltype( Func ) ),和auto一樣在編譯時確定類型
4.4 追蹤返回類型,使用auto和decltype可以追蹤返回類型
template<typename T1, typename T2>
auto Sum(T1 & t1, T2 & t2) -> decltype(t1 + t2) {
    return t1 + t2;
}

auto (*fp)() -> int;  等價於  int (*fp)();

 
5.1 強類型枚舉
     enum class Type: char { General, Light, Medium, Heavy };
 
6.1.2 常量表達式函數 constexpr
     函數必須有返回值
     函數體只有單一的return返回語句,函數體只有一條語句,且這條語句是return。可以有static_assert
     在使用前必須已有定義
     return 返回語句表達式中不能使用非常量表達式的函數、全局數據,且必須是一個常量表達式
     常量表達式的構造函數約束:函數體必須為空;初始化列表只能由常量表達式來賦值。
6.1.3 常量表達式值
const int i = 1; 與 constexpr int j = 1; 大部分情況下相同,區別是如果 i 在全局名字空間中,編譯器一定會為 i 產生數據,而對於 j ,如果不是有代碼顯示地使用了它的地址,編譯器可以選擇不為它產生數據,而僅將其當做編譯器的值。
6.2.2 變長模板
     template <typename… Elements> class tuple;   // Elements為模板參數包
6.3.2 原子操作 atomic
     atomic_llong total {0}; //原子數據類型,多線程訪問時不需要加鎖
     std::atomic<T> t; //atomic類模板,可以任意定義出需要的原子類型
     原子類型只能從其模板參數類型中進行構造,不允許原子類型進行拷貝構造、移動構造以及使用operator=等。
 
7.1.2 nullptr
     nullptr不能轉換為非指針類型,即使使用 reinterpret_cast<nullptr_t>()的方式也不可以
     nullptr不適用於算術運算表達式,也不能進行取地址操作
7.2.2 =default 顯式的聲明函數為缺省函數,=delete 顯式的聲明函數為刪除函數(不可使用和重載)
     顯示刪除也可以避免編譯器做一些不必要的隱式數據類型轉換,此時不要和explicit共同使用,如 void Func(char c) = delete; 會導致 Func(‘c’);無法通過編譯
7.3.2 lambda函數
     [capture] (parameters) mutable ->return-types {statement}
     lambda和仿函數類似,實際上仿函數是編譯器實現lambda的一種方式
     對於按值方式傳遞捕捉列表,傳遞的值在lambda函數定義的時候就決定了,而按引用方式傳遞的值則等於lamdba函數調用時的值。
     lambda的捕捉列表僅能捕捉父作用域的自動變量,而對超出這個范圍的變量是不能被捕捉的。
 
8.1.1 alignas 可以設定結構體的對齊方式,alignof獲取結構體的對齊大小
struct alignas(32) AlignedColorVector {
    double r;
    double g;
    double b;
    double a;
};
8.2.2 通用屬性,使用左右雙中括號包含
[[ attribute-list ]]
[[ attr1 ]] void fun [[ attr2 ]] ();
[[ attr1 ]] int array [[ attr2 ]] [10];
C++11中的預定義通用屬性包括 [[ noreturn ]] 標識不會返回的函數,[[ carries_dependency ]] 標識不會將控制流返回給原調用函數的函數,如
[[ noreturn ]] void ThrowAway() {
     throw "exception”;
}
8.3.2 UTF-8 采用的變長存儲方式,無法通過數字式訪問讀取數據,更多的使用序列化時節省存儲空間。定長的UTF-16或UTF-32更適合在內存環境中操作。
 
其他:
     在C++11中std的bind1st和bind2st被bind模板所代替 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM