C++11中值得關注的幾大變化

來源:互聯網
上載者:User

賴勇浩(http://laiyonghao.com)
聲明:本文源自 Danny Kalev 在 2011 年 6 月 21 日發表的《The Biggest Changes in C++11(and Why You Should Care)》一文,幾乎所有內容都搬了過來,但不是全文照譯,有困惑之處,請參詳原文(http://www.softwarequalityconnection.com/2011/06/the-biggest-changes-in-c11-and-why-you-should-care/
)。
註:作者 Danny Kalev 曾是 C++ 標準委員會成員。

Lambda 運算式

Lambda 運算式的形式是這樣的:
[capture](parameters)->return-type {body}
來看個計數某個字元序列中有幾個大寫字母的例子:
int main()<br />{<br /> char s[]="Hello World!";<br /> int Uppercase = 0; //modified by the lambda<br /> for_each(s, s+sizeof(s), [&Uppercase] (char c) {<br /> if (isupper(c))<br /> Uppercase++;<br /> });<br /> cout<< Uppercase<<" uppercase letters in: "<< s<<endl;<br />}
其中 [&Uppercase] 中的 & 的意義是 匿名函式體要擷取一個 Uppercase 引用,以便能夠改變它的值,如果沒有 &,那就 Uppercase 將以傳值的形式傳遞過去。

自動類型推導和 decltype

在 C++03 中,聲明對象的同時必須指明其類型,其實大多數情況下,聲明對象的同時也會包括一個初始值,C++11 在這種情況下就能夠讓你聲明對象時不再指定類型了:
auto x=0; //0 是 int 類型,所以 x 也是 int 類型<br />auto c='a'; //char<br />auto d=0.5; //double<br />auto national_debt=14400000000000LL;//long long
這個特性在對象的類型很大很長的時候很有用,如:
void func(const vector<int> &vi)<br />{<br /> vector<int>::const_iterator ci=vi.begin();<br />}
那個迭代器可以聲明為:
auto ci=vi.begin();
C++11 也提供了從對象或運算式中“俘獲”類型的機制,新的操作符 decltype 可以從一個運算式中“俘獲”其結果的類型並“返回”:
const vector<int> vi;<br />typedef decltype (vi.begin()) CIT;<br />CIT another_const_iterator;

統一的初始化文法

C++ 最少有 4 種不同的初始化形式,如括弧內初始化,見:
std::string s("hello");<br />int m=int(); //default initialization
還有等號形式的:
std::string s="hello";<br />int x=5;
對於 POD 集合,又可以用大括弧:
int arr[4]={0,1,2,3};<br />struct tm today={0};
最後還有建構函式的成員初始化:
struct S {<br /> int x;<br /> S(): x(0) {} };
這麼多初始化形式,不僅菜鳥會搞得很頭大,高手也吃不消。更慘的是 C++03 中居然不能初始化 POD 數組的類成員,也不能在使用 new[] 的時候初始 POD 數組,操蛋啊!C++11 就用大括弧一統天下了:
class C<br />{<br />int a;<br />int b;<br />public:<br /> C(int i, int j);<br />};<br />C c {0,0}; //C++11 only. 相當於 C c(0,0);<br />int* a = new int[3] { 1, 2, 0 }; /C++11 only<br />class X {<br /> int a[4];<br />public:<br /> X() : a{1,2,3,4} {} //C++11, 初始化數群組成員<br />};
還有一大好事就是對於容器來說,終於可以擺脫 push_back() 調用了,C++11中可以直觀地初始化容器了:
// C++11 container initializer<br />vector vs<string>={ "first", "second", "third"};<br />map singers =<br /> { {"Lady Gaga", "+1 (212) 555-7890"},<br /> {"Beyonce Knowles", "+1 (212) 555-0987"}};
而類中的資料成員初始化也得到了支援:
class C<br />{<br /> int a=7; //C++11 only<br />public:<br /> C();<br />};

deleted 函數和 defaulted 函數

像以下形式的函數:
struct A<br />{<br /> A()=default; //C++11<br /> virtual ~A()=default; //C++11<br />};
叫做 defaulted 函數,=default; 指示編譯器產生該函數的預設實現。這有兩個好處:一是讓程式員輕鬆了,少敲鍵盤,二是有更好的效能。
與 defaulted 函數相對的就是 deleted 函數:
int func()=delete;
這貨有一大用途就是實現 noncopyabe 防止對象拷貝,要想禁止拷貝,用 =deleted 聲明一下兩個關鍵的成員函數就可以了:
struct NoCopy<br />{<br /> NoCopy & operator =( const NoCopy & ) = delete;<br /> NoCopy ( const NoCopy & ) = delete;<br />};<br />NoCopy a;<br />NoCopy b(a); //編譯錯誤,拷貝建構函式是 deleted 函數

nullptr

nullptr 是一個新的 C++ 關鍵字,它是null 指標常量,它是用來替代高風險的 NULL 宏和 0 字面量的。nullptr 是強型別的:
void f(int); //#1<br />void f(char *);//#2<br />//C++03<br />f(0); //調用的是哪個 f?<br />//C++11<br />f(nullptr) //毫無疑問,調用的是 #2
所有跟指標有關的地方都可以用 nullptr,包括函數指標和成員指標:
const char *pc=str.c_str(); //data pointers<br />if (pc!=nullptr)<br /> cout<<pc<<endl;<br />int (A::*pmf)()=nullptr; //指向成員函數的指標<br />void (*pmf)()=nullptr; //指向函數的指標

委託建構函式

C++11 中建構函式可以調用同一個類的另一個建構函式:
class M //C++11 delegating constructors<br />{<br /> int x, y;<br /> char *p;<br />public:<br /> M(int v) : x(v), y(0), p(new char [MAX]) {} //#1 target<br /> M(): M(0) {cout<<"delegating ctor"<<end;} //#2 delegating
#2 就是所謂的委託建構函式,調用了真正的建構函式 #1。

右值引用

在 C++03 中的參考型別是只綁定左值的,C++11 引用一個新的參考型別叫右值參考型別,它是綁定到右值的,如臨時對象或字面量。
增加右值引用的主要原因是為了實現 move 語義。與傳統的拷貝不同,move 的意思是目標對象“竊取”原對象的資源,並將源置於“空”狀態。當拷貝一個對象時,其實代價昂貴且無必要,move 操作就可以替代它。如在 string 交換的時候,使用 move 意義就有巨大的效能提升,如原方案是這樣的:
void naiveswap(string &a, string & b)<br />{<br /> string temp = a;<br /> a=b;<br /> b=temp;<br />}
這種方案很傻很天真,很慢,因為需要申請記憶體,然後拷貝字元,而 move 就只需要交換兩個資料成員,無須申請、釋放記憶體和拷貝字元數組:
void moveswapstr(string& empty, string & filled)<br />{<br />//pseudo code, but you get the idea<br /> size_t sz=empty.size();<br /> const char *p= empty.data();<br />//move filled's resources to empty<br /> empty.setsize(filled.size());<br /> empty.setdata(filled.data());<br />//filled becomes empty<br /> filled.setsize(sz);<br /> filled.setdata(p);<br />}
要實現支援 move 的類,需要聲明 move 建構函式和 move 賦值操作符,如下:
class Movable<br />{<br />Movable (Movable&&); //move constructor<br />Movable&& operator=(Movable&&); //move assignment operator<br />};
C++11 的標準庫廣泛使用 move 語義,很多演算法和容器都已經使用 move 語義最佳化過了。

C++11 的標準庫

除 TR1 包含的新容器(unordered_set, unordered_map, unordered_multiset, 和unordered_multimap),還有一些新的庫,如Regex,tuple,函數對象封裝器等。下面介紹一些 C++11 的標準庫新特性:

線程庫

從程式員的角度來看,C++11 最重要的特性就是並發了。C++11 提供了 thread 類,也提供了 promise 和 future 用以並發環境中的同步,用 async() 函數模板執行並發任務,和 thread_local 儲存聲明為特定線程獨佔的資料,這裡(http://www.devx.com/SpecialReports/Article/38883)有一個簡單的 C++11 線程庫教程(英文)。

新的智能指標類

C++98 定義的唯一的智能指標類 auto_ptr 已經被棄用,C++11 引入了新的智能針對類 shared_ptr 和 unique_ptr。它們都是標準庫的其它組件相容,可以安全地把智能指標存入標準容器,也可以安全地用標準演算法“倒騰”它們。

新的演算法

主要是 all_of()、any_of() 和 none_of(),下面是例子:
#include <algorithm><br />//C++11 code<br />//are all of the elements positive?<br />all_of(first, first+n, ispositive()); //false<br />//is there at least one positive element?<br />any_of(first, first+n, ispositive());//true<br />// are none of the elements positive?<br />none_of(first, first+n, ispositive()); //false
還有一個新的 copy_n:
#include <algorithm><br />int source[5]={0,12,34,50,80};<br />int target[5];<br />//從 source 拷貝 5 個元素到 target<br />copy_n(source,5,target);
iota() 演算法可以用來建立遞增序列,它先把初值賦值給 *first,然後用前置 ++ 操作符增長初值並賦值到給下一個迭代器指向的元素,如下:
#include <numeric><br />int a[5]={0};<br />char c[3]={0};<br />iota(a, a+5, 10); //changes a to {10,11,12,13,14}<br />iota(c, c+3, 'a'); //{'a','b','c'}
是的,C++11 仍然缺少一些很有用的庫如 XML API,socket,GUI、反射——以及自動垃圾收集。然而現有特性已經讓 C++ 更安全、高效(是的,效率更高了,可以參見 Google 的 基準測試結果http://www.itproportal.com/2011/06/07/googles-rates-c-most-complex-highest-performing-language/)以及更加易於學習和使用。
如果覺得 C++ 變化太大了,不必驚恐,花點時間來學習就好了。可能在你融會貫通新特性以後,你會同意 Stroustrup 的觀點:C++11 是一門新的語言——一個更好的 C++。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.