日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++11 的新特性

發(fā)布時間:2025/6/15 c/c++ 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++11 的新特性 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

C++11 的新特性

1 變量和基本類型

1.1 long long 類型

擴展精度浮點數(shù),10位有效數(shù)字

1.2 列表初始化

初始化的幾種不同形式,其中用花括號來初始化變量稱為列表初始化;

比如:

int i = 0; int i = {0}; int i{0}; int i(0);

需要注意的是,當用于內(nèi)置類型的變量時,這種初始化形式有一個重要的特點:如果我們使用初始化且初始值存在丟失信息的風險,則編譯器報錯;

例如:

long double ld = 3.1414141414; int a{ld}, b = {ld}; //報錯 int c(ld), d = ld; //正確cout << "a:" << a << "b:" << b << "c:" << c << "d" << d << endl;

運行的時候,a,b則會提示報錯信息:error: type 'long double' cannot be narrowed to 'int' in initializer list [-Wc++11-narrowing],這是因為使用long double的值初始化int變量時可能會丟失數(shù)據(jù),所以拒絕a和b的初始化請求;雖然c,d雖然沒有報錯,但是確實丟失了數(shù)據(jù);

[這是為什么?]

1.3 nullptr 常量

有幾種生成空指針的方法:

int *p1 = nullptr; // 等價于int *p1 = 0; int *p2 = 0; int *p3 = NULL; // 等價于int *p3 = 0;

在新標準下,建議盡量使用新標準nullptr,nullptr是一種特殊類型的字面值,它可以被轉(zhuǎn)換成任意其它的指針類型,雖然其它的方式也是可以的;

1.4 constexpr 變量

將變量聲明為constexpr類型以便由編譯器來驗證變量的值是否是一個常量表達式;

聲明為constexpr的變量一定是一個常量,而且必須用常量表達式來初始化,比如說下面的情況則是不正確的:

int t = 10; constexpr int q = t + 20; cout << "q" << q << endl;

需要將t聲明為?const?才是正確的;

一般來說,如果你認定變量是一個常量表達式,那就把它聲明為constexpr類型;

1.5 類型別名聲明

使用類型別名可以使復雜的類型名字變得更簡單明了,易于理解和使用;

現(xiàn)在有兩種方法可以用來定義類型別名,一種是?typedef?,另一種則是新標準中的?using;

#include <iostream> using namespace std;int add(int val) {return 10 + val; }int main() {typedef double dnum;// 字符指針typedef char *pstring;// 函數(shù)// 返回值類型為int,參數(shù)類型為int的函數(shù)typedef int func(int);// 函數(shù)指針,指向返回值類型為int,參數(shù)類型為int的函數(shù)typedef int (*pfunc)(int);// 函數(shù)引用,指向返回值類型為int,參數(shù)類型為int的函數(shù)typedef int (&tfunc)(int);pfunc pfunc_add = nullptr;pfunc_add = add;cout << "函數(shù)指針,result is " << pfunc_add(10) << endl;tfunc tfunc_add = add;cout << "函數(shù)引用,result is " << tfunc_add(10) << endl;func &func_add = add; //這里使用指針或者引用都可以cout << "函數(shù),result is " << func_add(10) << endl;// 數(shù)組// 元素類型為int,個數(shù)為10的數(shù)組typedef int arr[10];// 數(shù)組指針,指向元素類型為int,個數(shù)為10的數(shù)組typedef int (*parr)[10];// 數(shù)組引用,綁定到元素類型為int,個數(shù)為10的數(shù)組typedef int (&tparr)[10];using dnum2 = double;using pstring2 = char*;using func2 = int(int);using pfunc2 = int(*)(int);using arr2 = int[10];using parr2 = int(*)[10];using tparr2 = int(&)[10];std::cout << "Hello, World!" << std::endl;return 0; }

但是需要注意的是,如果某個類型別名指代的是復合類型或者常量,那么就會產(chǎn)生意想不到的后果;

比如說

typedef char *pstring; const pstring cstr = 0;

按照我們正常的理解就是,將char*替換掉pstring,得到 const char* cstr;然而事實是pstring是一個字符指針,其基本數(shù)據(jù)類型是個指針,此時用此字符指針去聲明cstr,得到的是一個常量的字符指針,但是按照本意是指向char的常量指針,其基本類型是char,也就是說兩者修飾的東西是不一樣的!

但是如果是引用變量則沒有關(guān)系。

參考文章

C++ - 類型別名以及類型的自動推斷

C/C++ 函數(shù)指針的用法

1.6 auto 類型指示符

auto讓編譯器通過初始值來推算變量的類型,所以,其定義的變量必須要有初始值;

使用auto也能在一條語句中聲明多個變量;因為一條聲明語句只能有一個基本數(shù)據(jù)類型,所以該語句中所有的變量的初始基本數(shù)據(jù)類型都必須是一樣的;

  • 頂層const:指針本身是一個常量;
  • 底層const:指針指向的對象是一個常量;
int main() {int i = 0;const int ci = i;auto b = &i; // b是一個整形指針(整數(shù)的地址就是指向整數(shù)的指針)auto c = &ci; // c是一個指向整數(shù)常量的指針(對常量對象取地址是一種底層const)return 0; }

1.7 decltype 類型指示符

作用:選擇并返回操作數(shù)的數(shù)據(jù)類型;

1.7.1 decltype 和 auto 的區(qū)別

  • 處理頂層const和引用的方式

    const int ci = 0, &cj = ci; decltype(ci) x = 0; decltype(cj) y = x; decltype(cj) z; //報錯,因為cj是一個引用,因此作為引用的 z 必須要進行初始化

    引用從來都是作為其所指對象的同義詞出現(xiàn),也就是根據(jù)其所指的對象決定,只有在decltype處是個例外;

  • decltype的結(jié)果類型與表達式形式密切相關(guān)

    int i = 0; decltype((i)) a; //報錯,因為a類型為 int&,必須進行初始化 decltype(i) b; //正確

    需要注意的是,decltype((variable))的結(jié)果永遠是引用,而decltype(variable)結(jié)果只有當variable本身就是一個引用時才是引用,其實就是根據(jù)它的類型決定;

1.8 類內(nèi)初始化

建議初始化每一個內(nèi)置類型的變量,為了保證初始化后程序安全

2 字符串、向量和數(shù)組

2.1 使用 auto 或 decltype 縮寫類型

注意的是,如果表達式中已經(jīng)有了size函數(shù)就不要再使用int了,因為size函數(shù)返回的是unsigned,如果其和有符號數(shù)進行比較的時候,有符號數(shù)會自動的轉(zhuǎn)換成一個比較大的無符號數(shù)。

2.2 范圍 for 語句

string str("hello world"); for (auto c : str) {cout << c; }

2.3 定義vector對象的vector(向量的向量)

編譯器根據(jù)模版vector生成了三種不同的類型,分別是:

vector<int>,vector<vector<int>>, vector<classname>

新的版本已經(jīng)不需要再添加一個空格

vector<vector<int> >

2.4 vector對象的列表初始化

放在花括號里

2.5 容器的cbegin 和 cend 函數(shù)

2.6 標準庫begin 和 end 函數(shù)

2.7 使用auto和decltype簡化聲明

3 表達式

3.1 除法的舍入規(guī)則

新標準中,一律向0取整(直接切除小數(shù)部分)

double a = 12/5; cout << a << endl;

輸出結(jié)果為2,刪掉了小數(shù)部分;

3.2 用大括號包圍的值列表賦值

3.3 將sizeof用于類成員

使用作用域運算符來獲取類成員的大小是許可的;

  • 對數(shù)組執(zhí)行sizeof運算得到整個數(shù)組所占空間的大小,等價于對數(shù)組中
    所有的元素各執(zhí)行一次sizeof運算并將所得結(jié)果求和;
  • 對string對象或vector對象執(zhí)行sizeof運算只返回該類型固定部分的大小,不會計算對象中的元素占用多少空間;

4 語句

4.1 范圍for語句

5 函數(shù)

5.1 標準庫 initializer_list類

可以處理不同數(shù)量實參的函數(shù),前提是實參類型要相同

其提供的操作包括:

  • 默認初始化
  • 列表初始化
  • 拷貝對象
  • size
  • begin
  • end

5.2 列表初始化返回值

函數(shù)可以返回花括號包圍的值的列表,如果列表為空,臨時量執(zhí)行初始化,否則,返回的值由函數(shù)的返回類型決定;

vector<string> getAddress(int num) {if (num == 0) {return {};}return {"address1", "address2", "address3"}; }

5.3 定義尾置返回類型

任何函數(shù)的定義都能夠使用尾置來返回,最適用于返回類型比較復雜的情況;

比如:

// 返回類型為指針,該指針指向含有10個整數(shù)的數(shù)組 auto func(int i) -> int(*)[10] {int arr[10] = {0};return &arr; }

5.4 使用decltype簡化返回類型定義

int odd[] = {1, 3, 5, 7, 9}; int even[] = {2, 4, 6, 8, 10};// 返回一個指針,指向數(shù)組 decltype(odd) *getArr(int i) {return (i % 2) ? &odd : &even; }

decltype并不會因為獲取的是數(shù)組,則返回的是指針,還是需要在函數(shù)名前面加上?*;

5.5 constexpr函數(shù)

是指能用于常量表達式的函數(shù);

需要遵從幾項約定:

  • 函數(shù)的返回類型以及所有形參的類型都是字面值類型(只能用它的值來稱呼它);
  • 函數(shù)體中必須有且只有一條return語句(C++14不再做要求);
  • 必須非virtual
constexpr int func2() {return 10; }int main() {int arr[func2() + 10] = {0};return 0; }

6 類

6.1 使用=default生成默認構(gòu)造函數(shù)

如果實現(xiàn)了默認的構(gòu)造函數(shù),編譯器則不會自動生成默認版本;可以通過使用關(guān)鍵字?default?來控制默認構(gòu)造函數(shù)的生成,顯示的指示編譯器生成該函數(shù)的默認版本;

class MyClass{ public:MyClass()=default; //同時提供默認版本和帶參版本MyClass(int i):data(i){} private:int data; };

比如說如果想要禁止使用拷貝構(gòu)造函數(shù),則使用關(guān)鍵字?delete;

class MyClass { public:MyClass()=default;MyClass(const MyClass& )=delete; };int main() {MyClass my;MyClass my2(my); //報錯return 0; }

但需要注意的是,析構(gòu)函數(shù)是不允許使用delete的,否則無法刪除;

6.2 類對象成員的類內(nèi)初始化

當提供一個類內(nèi)初始值時,必須以符號=或者花括號表示

6.3 委托構(gòu)造函數(shù)

一個委托構(gòu)造函數(shù)使用它所屬類的其它構(gòu)造函數(shù)執(zhí)行它自己的初始化過程,或者說它把它自己的一些(或者全部)指責委托給了其它構(gòu)造函數(shù);

class MyClass { public:MyClass() : MyClass(10) {}MyClass(int d) : data(d){}inline int getData() {return data;} private:int data; };int main() {MyClass my;cout << my.getData() << endl;return 0; }

6.4 constexpr構(gòu)造函數(shù)

如果想要使得函數(shù)擁有編譯時計算的能力,則使用關(guān)鍵字?constexpr

同樣的編譯時使用對象:

class Square { public:constexpr Square(int e) : edge(e){};constexpr int getArea() {return edge * edge;} private:int edge; };int main() {Square s(10);cout << s.getArea() << endl;return 0; }

如果成員函數(shù)標記為?constexpr,則默認其是內(nèi)聯(lián)函數(shù),如果變量聲明為
constexpr,則默認其是?const;

參考文章

constexpr指定符(C++11 起)

7 IO庫

7.1 用string對象處理文件名

新版本中增加了使用庫類型string對象作為文件名,之前只能使用C風格的字符數(shù)組;

ifstream infile("/hello.sh");

8 順序容器

補充:

順序容器的類型:

容器描述
vector可變大小數(shù)組。支持快速隨機訪問。在尾部之外的位置插入或者刪除元素時可能很慢
deque雙端隊列。支持快速隨機訪問。在頭尾位置插入/刪除速度很快
list雙向鏈表。只支持雙向雙向順序訪問。在list中任何位置進行插入/刪除操作
forward_list單向鏈表。只支持單向順序訪問。在鏈表任何位置進行插入/刪除操作都很快
array固定大小數(shù)組。支持快速隨即訪問。不能添加或刪除元素
string與vector相似的容器,但專門用于保存字符(字符數(shù)組,封裝了char而已)。隨機訪問速度快,在尾部插入、刪除速度快

總而言之,數(shù)組隨機訪問速度快,鏈表插入刪除速度快;

8.1 array和forward_list容器

  • array

    #include <string> #include <iterator> #include <iostream> #include <algorithm> #include <array>int main() {// 使用聚合初始化來構(gòu)造std::array<int, 3> a1{ {1,2,3} }; // C++11中需要使用雙重花括號(而14中不需要)std::array<int, 3> a2 = {1, 2, 3}; // 不再需要等號了std::array<std::string, 2> a3 = { {std::string("a"), "b"} };// 支持基本的容器操作std::sort(a1.begin(), a1.end());std::reverse_copy(a2.begin(), a2.end(), std::ostream_iterator<int>(std::cout, " "));// 支持范圍forfor(auto& s: a3)std::cout << s << ' '; }
  • forward_list

    和?list?的使用類似,就不貼代碼了;

    template < class T, class Alloc = allocator<T> > class forward_list;

    Alloc,容器內(nèi)部用來管理內(nèi)存分配以及釋放的內(nèi)存分配器的類型,默認使用的是?std::allocator<T>,;

參考文章

std::array

std::forward_list

8.2 容器的cbegin和cend函數(shù)

返回的是const的迭代器,當不需要寫訪問時,應(yīng)使用cbegin和cend;

8.3 容器的列表初始化

8.4 容器的非成員函數(shù)swap

除了?array?外,swap不對任何元素進行拷貝、刪除或者插入操作,因此可以保證常數(shù)時間內(nèi)完成;swap 只是交換了容器內(nèi)部數(shù)據(jù)結(jié)構(gòu),不會交換元素,因此,除string?外,指向容器的迭代器、引用和指針在 swap 操作后都不會失效;

但是,array會真正的交換它們的元素。

8.5 容器insert成員的返回類型

在新標準下,接受元素個數(shù)或范圍的insert版本返回的是-指向第一個新加入元素的迭代器;

如果范圍為空,不插入任何元素,insert?操作會將第一個參數(shù)返回;

int main() {list<string> lst;auto itr = lst.begin();string word;while (cin >> word) {itr = lst.insert(itr, word); //等價于push_front}return 0; }

8.6 容器的emplace成員

當調(diào)用?push?或?insert?成員函數(shù)時,我們將元素類型的對象傳遞給它們,這些對象被拷貝到容器里面,但是,當我們調(diào)用一個?emplace?成員函數(shù)時,則是將函數(shù)傳遞給元素類型的構(gòu)造函數(shù),會使用這些參數(shù)在容器管理的內(nèi)存中直接構(gòu)造元素;包括三個函數(shù):emplace_front,emplace,emplace_back,分別對應(yīng)著?push_front,insert,push_back?為頭部,指定位置,尾部;

class MyClass { public:MyClass(int d) : data(d){}inline int getData() {return data;} private:int data; };int main() {vector<MyClass> mys;mys.emplace_back(10);mys.push_back(MyClass(20));for (auto itr = mys.begin(); itr != mys.end(); itr++) {cout << (*itr).getData() << endl;}return 0; }

8.7 shrink_to_fit

調(diào)用該函數(shù)要求?deque,vector,string?退回不需要的內(nèi)存空間;

int main() {vector<int> nums;nums.push_back(10);nums.push_back(10);nums.push_back(10);nums.push_back(10);nums.push_back(10);cout << nums.capacity() << endl;nums.shrink_to_fit();cout << nums.capacity() << endl;return 0; }

返回結(jié)果為8,5

區(qū)別:

  • reserve:預分配存儲區(qū)大小,即capacity的值
  • resize:容器大小,即size的值

8.9 string的數(shù)值轉(zhuǎn)換函數(shù)

新標準中,引入多個函數(shù)實現(xiàn)數(shù)值數(shù)據(jù)和標準庫string之間的轉(zhuǎn)換:

函數(shù)描述
to_string(val)返回任意算術(shù)類型val的字符串
stoi(s, p, b)int類型
stol(s, p, b)long類型
stoul(s, p, b)unsigned long類型
stoll(s, p, b)long long類型
stoull(s, p, b)unsigned long long類型
stof(s, p, b)float類型
stod(s, p, b)double類型
stold(s, p, b)long double類型

9 泛型算法

9.1 lambda表達式

一個lambda具有一個返回類型、一個參數(shù)列表和一個函數(shù)體;

[capture list](parameter list) -> return type { function body }

9.2 lambda表達式中的尾置返回類型

9.3 標準庫bind函數(shù)

auto newCallable = bind(callable, arg_list);

例子(綁定類成員函數(shù))

#include <iostream> #include <functional> using namespace std; using namespace std::placeholders; class MyClass { public:void fun1(void){cout << "void fun1(void)" << endl;}int fun2(int i){cout << "int fun2(int i)" << " i = " << i << endl;return i;} }; int main() {MyClass my;//使用類對象綁定auto fun1 = bind(&MyClass::fun1, my);fun1();MyClass *p;//使用類指針綁定,-1為占位符auto fun2 = bind(&MyClass::fun2, p, _1);int i = fun2(1);cout << "i = " << i << endl;cin.get();return 0; }

10. 關(guān)聯(lián)容器

關(guān)聯(lián)器類型

  • map 關(guān)聯(lián)數(shù)組,保存關(guān)鍵字-值對
  • set 關(guān)鍵字即值,即只保存關(guān)鍵字的容器
  • multimap 關(guān)鍵字可重復出現(xiàn)的map
  • multiset 關(guān)鍵字可重復出現(xiàn)的set
  • unordered_map 用哈希函數(shù)組織的map
  • unordered_set 用哈希函數(shù)組織的set
  • unordered_multimap 用哈希函數(shù)組織的map,關(guān)鍵字可重復
  • unordered_multiset 用哈希函數(shù)組織的set,關(guān)鍵字可重復

10.1 關(guān)聯(lián)容器的列表初始化

和順序容器差不多

10.2 列表初始化pair的返回類型

10.3 pair的列表初始化

10.4 無序容器

包括4個無序關(guān)聯(lián)容器(使用哈希函數(shù)和關(guān)鍵字類型的 == 運算符)

  • unordered_map
  • unordered_set
  • unordered_multiset
  • unordered_multimap

11 動態(tài)內(nèi)存

已總結(jié),略

11.1 智能指針

11.2 shared_ptr類

11.3 動態(tài)分配對象的列表初始化

11.4 auto和動態(tài)分配

11.5 unique_ptr類

11.6 weak_ptr類

11.7 范圍for語句不能應(yīng)用于動態(tài)分配數(shù)組

因為分配的內(nèi)存并不是一個數(shù)組類型

11.8 動態(tài)分配數(shù)組的列表初始化

可以對數(shù)組中的元素進行值初始化,方法是在大小之后跟一對括號;

int *pia = new int[10]; //10個未初始化的int int *pia2 = new int[10](); //10個初始化為0的int int *pia3 = new int[10]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};delete [] pia; //釋放 delete [] pia2; delete [] pia3;

11.9 auto不能用于分配數(shù)組

雖然我們用空括號對數(shù)組中元素進行值初始化,但不能在括號中給出初始化器,這意味著不能用auto分配數(shù)組;

11.10 allocator::construct可使用任意構(gòu)造函數(shù)

allocator分配的內(nèi)存是未構(gòu)造的,我們按需要在此內(nèi)存中構(gòu)造對象。在新標準庫中,construct成員函數(shù)接受一個指針和零個或多個額外參數(shù),在給定位置構(gòu)造一個元素。

int main() {allocator<string> alloc;string* str = alloc.allocate(4); //分配10個未初始化的stringauto itr = str;alloc.construct(itr, "chengdu"); //chengducout << str[0] << endl;itr++;alloc.construct(itr, "beijing"); //beijingcout << str[1] << endl;itr++;alloc.construct(itr, 10, 'c'); //10個c組成的字符串cout << str[2] << endl;itr++;alloc.construct(itr); //空字符串cout << str[3] << endl;for (int i = 0; i < 4; i++) {cout << str[i] << endl;}// 銷毀while (itr != str) {alloc.destroy(itr--);}return 0; }

為了使用allocate返回的內(nèi)存,我們必須用construct構(gòu)造對象,使用未構(gòu)造的內(nèi)存,其行為是未定義的;我們只有對真正構(gòu)造了的元素進行destroy操作;

12 拷貝控制

12.1 將=default用于拷貝控制類對對象

可以類內(nèi)或者類外修飾成員函數(shù),如果是類內(nèi),合成的函數(shù)將隱式地聲明未內(nèi)聯(lián)的,如果不希望這樣,則在類外聲明;

我們只能對具有合成版本的成員函數(shù)使用=default(即,默認構(gòu)造函數(shù)或拷貝控制成員)

12.2 使用=delete用于拷貝控制成員

對于析構(gòu)函數(shù)已刪除的類型,不能定義該類型的變量或釋放指向該類型動態(tài)分配的指針;

12.3 用移動類對象代替拷貝類對象

為了解決之前存在的性能問題,避免不必要的內(nèi)存拷貝,新標準中有兩種方法來替代拷貝函數(shù):移動函數(shù)和?move

移動構(gòu)造函數(shù)

A(A && h) : a(h.a){h.a = nullptr; }

12.4 右值引用

右值引用就是必須綁定到右值的引用,通過?&&?來獲得右值引用;

12.4.1 區(qū)別左值和右值

  • 左值:在賦值號左邊,可以被賦值的值,可以取地址;
  • 右值:在賦值號右邊,取出值賦給其他變量的值;

  • 左值引用:type & 引用名 = 左值表達式
  • 右值引用:type && 引用名 = 右值表達式

int a = 0; //2int b = a; //1

一個對象被用作右值時,使用的是它的內(nèi)容(值),比如1中的?a?,被當作左值時,使用的是它的地址,比如2中的?a,常規(guī)左值;

int main() {int i = 1; //i為常規(guī)左值int &r = i; //正確:r綁定到i上,r是一個引用int &&rr = i; //錯誤:不能將一個右值引用綁定到左值i上int &r2 = i * 1; //錯誤:等號右邊是一個右值,但左值引用只能綁定到左值上int &&rr2 = i * 1; //正確:右值引用綁定到右值上const int &r3 = i * 1; //正確:可以將一個const的左值引用綁定到右值上return 0; }
  • 返回左值引用的函數(shù)、賦值、下標、解引用和前置遞增/遞減運算符,都是返回左值的表達式的例子,我們可以將一個左值引用綁定到這類表達式的結(jié)果上;

  • 返回非引用類型的函數(shù),連同算術(shù)、關(guān)系、位以及后置遞增/遞減運算符,都生成右值;我們不能將左值引用綁定到這類表達式上,但是我們可以將一個const的左值引用或者一個右值引用綁定到這類表達式之上;

12.5 標準庫move函數(shù)

我們可以銷毀一個移后源對象,也可以賦予它新值,但不能使用一個移后源對象的值

// 移動構(gòu)造函數(shù),參數(shù) "arg.member" 是左值 A(A&& arg) : member(std::move(arg.member)) { } // 移動賦值函數(shù) A& operator=(A&& other) {member = std::move(other.member);return *this; }

12.6 移動構(gòu)造函數(shù)和移動賦值

12.7 移動構(gòu)造函數(shù)通常是noexcept

如果需要通知標準庫這是一個不會拋出異常的移動操作,可以在函數(shù)后面指明?noexcept,如果在一個構(gòu)造函數(shù)中,noexcept?出現(xiàn)在參數(shù)列表和初始化列表開始的冒號之間;

不拋出異常的移動構(gòu)造函數(shù)和移動賦值運算符必須標記為noexcept

12.8 移動迭代器

新標準中可以通過調(diào)用標準庫的?make_move_iterator?函數(shù)將一個普通迭代器轉(zhuǎn)換為一個移動迭代器,這樣可以避免拷貝操作帶來的性能問題;

#include <iostream> // std::cout #include <iterator> // std::make_move_iterator #include <vector> // std::vector #include <string> // std::string #include <algorithm> // std::copyint main() {std::vector<std::string> foo(3);std::vector<std::string> bar{ "one","two","three" };std::copy(make_move_iterator(bar.begin()),make_move_iterator(bar.end()),foo.begin());// bar now contains unspecified values; clear it:bar.clear();std::cout << "foo:";for (std::string& x : foo) std::cout << ' ' << x;std::cout << '\n';return 0; }

12.9 引用限定成員函數(shù)

引用限定符可以是?&?或者?&&,分別指出?this?可以指向一個左值或者右值,引用限定符只能用于成員函數(shù),而且必須同時出現(xiàn)在函數(shù)的聲明和定義中;

可以在參數(shù)列表之后使用引用限定符來指定this對象的左值與右值屬性;

  • 若引用限定符為&,則表明this對象指向著左值對象;
  • 若引用限定符為&&,則表明this對象指向著右值對象;

參考文章

C++-引用限定符

13 重載運算與類型轉(zhuǎn)換

13.1 function類模版

function模版提供一種通用、多態(tài)的函數(shù)封裝。其實例可以對任何可調(diào)用的目標進行存儲、賦值和調(diào)用操作,這些目標包括函數(shù)、lambda表達式、綁定表達式以及其它函數(shù)對象等;

#include <functional> #include <iostream>struct Foo {Foo(int num) : num_(num) {}void print_add(int i) const { std::cout << num_+i << '\n'; }int num_; };void print_num(int i) {std::cout << i << '\n'; }struct PrintNum {void operator()(int i) const{std::cout << i << '\n';} };int main() {// 保存自由函數(shù)std::function<void(int)> f_display = print_num;f_display(-9);// 保存 lambda 表達式std::function<void()> f_display_42 = []() { print_num(42); };f_display_42();// 保存 std::bind 的結(jié)果std::function<void()> f_display_31337 = std::bind(print_num, 31337);f_display_31337();// 保存成員函數(shù)std::function<void(const Foo&, int)> f_add_display = &Foo::print_add;Foo foo(314159);f_add_display(foo, 1);// 保存成員函數(shù)和對象using std::placeholders::_1;std::function<void(int)> f_add_display2= std::bind( &Foo::print_add, foo, _1 );f_add_display2(2);// 保存成員函數(shù)和對象指針std::function<void(int)> f_add_display3= std::bind( &Foo::print_add, &foo, _1 );f_add_display3(3);// 保存函數(shù)對象std::function<void(int)> f_display_obj = PrintNum();f_display_obj(18); }

13.2 explicit類型轉(zhuǎn)換運算符

用來防止由構(gòu)造函數(shù)定義的隱式轉(zhuǎn)換;

看看構(gòu)造函數(shù)的隱式轉(zhuǎn)換,如果類的構(gòu)造函數(shù)有一個參數(shù),那么在編譯的時候就會有一個缺省的轉(zhuǎn)換操作,會將其參數(shù)轉(zhuǎn)化成類的對象;

class MyClass { public: MyClass( int num ); } // 編譯器會將10轉(zhuǎn)換成MyClass對象 MyClass obj = 10;

避免這種自動轉(zhuǎn)換的操作則需要?explicit:

class MyClass { public: explicit MyClass( int num ); } MyClass obj = 10; //err,can't non-explict convert

其只能用在類內(nèi)部的構(gòu)造函數(shù)聲明上,不能用在類外部的函數(shù)定義上;

被聲明為explicit的構(gòu)造函數(shù)通常比其non-explicit兄弟更受歡迎。因為它們禁止編譯器執(zhí)行非預期(往往也不被期望)的類型轉(zhuǎn)換。除非我有一個好理由允許構(gòu)造函數(shù)被用于隱式類型轉(zhuǎn)換,否則我會把它聲明為explicit。---Effective c++

14 面向?qū)ο蟪绦蛟O(shè)計

14.1 虛函數(shù)的override和final指示符

override?可以幫助程序員的意圖更加的清晰的同時讓編譯器可以為我們發(fā)現(xiàn)一些錯誤。其只能用于覆蓋基類的虛函數(shù)

final?使得任何嘗試覆蓋該函數(shù)的操作都將引發(fā)錯誤,并不特指虛函數(shù);

均出現(xiàn)在形參列表(包括任何const或者引用限定符)以及尾置返回類型之后

14.2 刪除的拷貝控制和繼承

如果函數(shù)在基類中被定義為是刪除的,則派生類對應(yīng)的也是刪除的;

14.3 繼承的構(gòu)造函數(shù)

委派和繼承構(gòu)造函數(shù)是由C++11引進為了減少構(gòu)造函數(shù)重復代碼而開發(fā)的兩種不同的特性;

a. 通過特殊的初始化列表語法,委派構(gòu)造函數(shù)允許類的一個構(gòu)造函數(shù)調(diào)用其它的構(gòu)造函數(shù)

X::X(const string& name) : name_(name) {... }X::X() : X("") { }

b. 繼承構(gòu)造函數(shù)允許派生類直接調(diào)用基類的構(gòu)造函數(shù),一如繼承基類的其它成員函數(shù),而無需重新聲明,當基類擁有多個構(gòu)造函數(shù)時這一功能尤其有用:

class Base {public:Base();Base(int n);Base(const string& s);... };class Derived : public Base {public:using Base::Base; // Base's constructors are redeclared here. };

using聲明語句將令編譯器產(chǎn)生代碼,對于基類的每個構(gòu)造函數(shù),編譯器都在派生類中生成一個形參列表完全相同的構(gòu)造函數(shù);如果派生類含有自己的數(shù)據(jù)成員,則這些成員將會被默認初始化;

15 模版與泛型編程

15.1 聲明模版類型形參為友元

在新標準中,我們可以將模板類型參數(shù)聲明為友元:

template <typename Type> class Bar {friend Type; //將訪問權(quán)限授予用來實例化Bar的類型 };

此處我們將用來實例化Bar的類型聲明為友元。因此,對于某個類型名Foo,Foo?將成?Bar<Foo>?的友元。

15.2 模版類型別名

新標準中允許我們?yōu)槟0娑x一個類型別名:

template<typename T> using twin = pair<T, T>; twin<string> authors;

其中,twin是一個?pair<T,T>;

15.3 模版函數(shù)的默認模版參數(shù)

template <typename T, typename F = less<T>> int compare(const T &v1, const T &v2, F f= F()) {if (f(v1, v2)) return -1;if (f(v2, v1)) return 1;return 0; }

就像之前能為函數(shù)參數(shù)提供默認實參一樣,compare有一個默認模版實參?less<T>和一個默認函數(shù)實參?F()

參考文章

C++類模板與友元的關(guān)系

15.4 實例化的顯示控制

顯示實例化:在不發(fā)生函數(shù)調(diào)用的時候?qū)?span style="margin:0px;padding:0px;">函數(shù)模版實例化或者在不適用類模版的時候?qū)?span style="margin:0px;padding:0px;">類模版實例化,這可以避免實例化相同的模版所帶來的額外開銷

  • 函數(shù)模版實例化
template函數(shù)返回類型 函數(shù)模板名<實際類型列表>(函數(shù)參數(shù)列表)
  • 類模版實例化
template class 類模板名<實際類型列表>

參考文章

C++模板之隱式實例化、顯示實例化、顯示調(diào)用、隱式調(diào)用和模板特化詳解

15.5 模版函數(shù)與尾置返回類型

例子:

//尾置返回允許我們在參數(shù)列表之后聲明返回類型 template <typename T> auto func(T beg, T end) -> decltype(*beg) {return *beg; //返回序列中一個元素的引用 }

15.6 引用折疊規(guī)則

規(guī)則如下:

  • 所有右值引用折疊到右值引用上仍然是一個右值引用,比如(A&& && 變成 A&&)
  • 所有的其它引用類型之間的折疊都將會變成左值引用,比如(A& &變成A&,A& && 變成 A&,A&& & 變成 A&)

引用折疊只能應(yīng)用于間接創(chuàng)建的引用的引用,如類型別名或者模版參數(shù);

15.7 用static_cast將左值轉(zhuǎn)換為右值

可以通過類型轉(zhuǎn)換?static_cast<Type&&>?來將返回右值引用;

int s=101;int&& foo(){return static_cast<int&&>(s); } //返回值為右值引用int main() {int i=foo(); //右值引用作為右值,在賦值運算符的右側(cè)int&& j=foo(); //j是具名引用。因此運算符右側(cè)的右值引用作為左值int* p=&j; //取得j的內(nèi)存地址 }

參考文章

右值引用

15.8 標準庫forward函數(shù)

右值引用至少解決了兩個問題:

  • 實現(xiàn)?move?語義
  • 完美轉(zhuǎn)發(fā)
  • 完美轉(zhuǎn)發(fā)

    有的時候,我們需要將一個函數(shù)中某一組參數(shù)原封不動的傳遞給另一個函數(shù),這里不僅僅需要參數(shù)的值不變,而且需要參數(shù)的類型屬性(左值/右值)保持不變-完美轉(zhuǎn)發(fā);

    使用forward

    • 原型:
    template< class T > constexpr T&& forward( typename std::remove_reference<T>::type& t );template< class T > constexpr T&& forward( typename std::remove_reference<T>::type&& t );
    • 例子:
    #include <iostream> #include <utility> #include <memory> class A { public:A(int && n) { std::cout << "rvalue constructor -> n=" << n << std::endl;}A(int& n) { std::cout << "lvalue constructor -> n=" << n << std::endl;} }; template<class T, class U> std::unique_ptr<T> make_unique1(U&& u) {return std::unique_ptr<T>(new T(std::forward<U>(u)));//return std::unique_ptr<T>(new T(u)); } int main() {int i = 24;auto p1 = make_unique1<A>(666); // rvalue forwardingauto p2 = make_unique1<A>(i); // lvalue forwardingauto p3 = make_unique1<A>(std::move(i)); // rvalue forwardingreturn 0; }

    但是如果我們沒有使用?forward?函數(shù),結(jié)果則全部都調(diào)用的是 lvalue constructor;

    參考文章

    Modern C++ | 移動語義與完美轉(zhuǎn)發(fā) | Universal Reference

    移動語義(move semantic)和完美轉(zhuǎn)發(fā)(perfect forward)

    15.9 可變參數(shù)模版與轉(zhuǎn)發(fā)

    右值引用+完美轉(zhuǎn)發(fā)+可變參數(shù)模版實現(xiàn)下面這個函數(shù);

    // args為右值引用,decltype用于返回值 template<class Function, class... Args> auto FuncWrapper(Function && f, Args && ... args) -> decltype(f(std::forward<Args>(args)...)) {return f(std::forward<Args>(args)...); }void test0() {cout <<"void"<< endl; }int test1() {return 1; }int test2(int x) {return x; }string test3(string s1, string s2) {return s1 + s2; }int main() {int num = 10;int && nnum = num + 10;int & nnum2 = num;FuncWrapper(test0); // 沒有返回值,打印1cout << FuncWrapper(test1) << endl; // 沒有參數(shù),有返回值,返回1cout << FuncWrapper(test2, 1) << endl; // 有參數(shù),有返回值,返回1cout << FuncWrapper(test2, std::move(num)) << endl; // 有參數(shù),有返回值,返回左值10cout << FuncWrapper(test2, std::move(nnum2)) << endl; // 有參數(shù),有返回值,返回左值引用10cout << FuncWrapper(test2, nnum) << endl; // 有參數(shù),有返回值,返回右值引用20cout << FuncWrapper(test3, "aa", "bb") << endl; // 有參數(shù),有返回值,返回"aabb"return 0; }

    返回值分別為:

    void 1 1 10 10 20 aabb

    總結(jié)

    以上是生活随笔為你收集整理的C++11 的新特性的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。