C++11新特性(三):語言特性

LemHou發表於2024-08-24

C++11新特性

範圍for迴圈

std::vector<int> nums;
for (auto it : nums){
    cout << *it << endl;
}
array<5, int> a{1, 2, 3 ,4 ,5};
for (auto x : a){
    x *= 2; // 此時a中元素不會發生改變a{1, 2, 3, 4, 4}
}
for (auto& x : a){
    x *= 2; // 此時a中元素會發生改變a{2, 4, 6, 8, 8}
}
for_each(a.begin(), a.end(), [](int x){x*=2;}) // a中元素不會發生改變

移動語義特殊成員函式

參見st::move()實現移動建構函式和移動賦值運算子

轉換構造器

轉換構造器支援花括號列表語義到引數的轉換

class MyClass{
pulic:
    MyClass(int){}
    MyClass(int, int){}
};
MyClass b{1,2};

顯式轉換函式

explict可用於類構造器和運算子中禁止隱式轉換,比如禁止基礎資料型別直接隱式轉換為類物件。

class MyClass{
     explict MyClass(int){
    	/* code */
	}  
};
void Func(MyClass a){
    
}
MyClass a(1.1); // OK, 只是float->int的隱式轉換,不涉及到類物件的轉換,此時是可行的。
Func(1.1); // Error, 此時會涉及float->MyClass的隱式轉換,但是由於explict宣告會拒絕隱式型別轉換
Func(MyClass(1.1)); // OK, 顯示指明轉換型別

內聯名稱空間

內聯空間可以使該空間像是父空間的一部分。

namespace Parent{
    namespace Cousin{
        void GetCousinName(){}
    }
    inline namespace Son{
        void GetSonName(){}
    }
}
Parent::Cousin::GetCousinName(); // 巢狀的名稱空間的作用域在巢狀作用域中,也是侄子有私人空間
Parent::GetSonName(); // 內聯名稱空間作用域在父空間中,兒子沒有私人空間。
using Parent::Cousin::GetCousinName; // 匯入名稱空間中的函式
GetCousinName();
namespace cousin = Parent::Cousin; //名稱空間別名

非靜態資料成員初始化

C++11允許非靜態成員初始化。

class Cat{
    Cat(int a) : val(a){}
    int val = 0; // 允許非靜態成員直接初始化
    int name {0};
};

右角括號

map<map<int, int>>; // C++11才支援可以無空格連續右角括號

引用限定成員函式

引用限定成員函式能夠檢查物件的*this是一個左值引用還是右值引用

class Cat{
public:
    Cat(int a) : val(a){}
    void GetName() &{
        cout << "lvalue" << endl;
    }
    void GetName() &&{
        cout << "rvalue" << endl;
    }
private:
    int val = 0; // 允許非靜態成員直接初始化
    int name {10};
};
int main()
{
    Cat s(5);
    s.GetName(); // 左值呼叫GetName() &
    move(s).GetName(); // 右值引用呼叫GetName() && 
    Cat&& m = move(s);
    m.GetName(); // lvalue,此時就會出現右值傳入時會退化為左值
}

尾部返回型別

允許使用->來為lambda和不明確函式返回型別指定返回型別。

auto Func1() -> int{
    /* code */
}
auto Func2 = []() -> int{};

noexcept限定符

noexcept關鍵字告訴編譯器該函式不會丟擲任何異常,從而允許編譯器最佳化。如果丟擲了異常,會用std::terminate終止程式執行。可以省略一些編譯器生成一些異常處理程式碼。可以是條件性判斷丟擲異常。noexcept常用於修飾需要更改資源訪問的函式,比如預設建構函式、解構函式、移動建構函式、移動賦值運算子、複製建構函式、複製賦值運算子。

void Add(int a, int b) noexcept{
    // 不會丟擲任何異常
}
void AddIf(int a, int b) noexcept(false){
    // 可能會丟擲異常
}

char32_tchar16_t標準型別

char32_t char16_t代表UTF-8字串(1-4個位元組)

原始字面字串

舉例完成對原生字面字串語法的展現

const char* str = "hello,\nworld\n";
// 等價於
const char* str = R"(hello,
world)";

相關文章