一、Lambda表達式的引進
Lambda表達式的形式是這樣的:
[capture](parameters)->return-type{body}
來看個計數某個字符序列中有幾個大寫字母的例子:
1. intmain()
2. {
3. chars[]="HelloWorld!";
4. intUppercase=0;//modifiedbythelambda
5. for_each(s,s+sizeof(s),[&Uppercase](charc){
6. if(isupper(c))
7. Uppercase++;
8. });
9. cout<<Uppercase<<"uppercaselettersin:"<<s<<endl;
10. }
其中[&Uppercase]中的 &的意義是 lambda函數體要獲取一個 Uppercase引用,以便能夠改變它的值,如果沒有 &,那就 Uppercase將以傳值的形式傳遞過去。
二、自動類型推導和decltype
在 C++03中,聲明對象的同時必須指明其類型,其實大多數情況下,聲明對象的同時也會包括一個初始值,C++11在這種情況下就能夠讓你聲明對象時不再指定類型了:
1. autox=0;//0是int類型,所以x也是int類型
2. autoc='a';//char
3. autod=0.5;//double
4. autonational_debt=14400000000000LL;//longlong
這個特性在對象的類型很大很長的時候很有用,如:
1. voidfunc(constvector<int>&vi)
2. {
3. vector<int>::const_iteratorci=vi.begin();
4. }
那個迭代器可以聲明為:
1. autoci=vi.begin();
C++11也提供了從對象或表達式中“俘獲”類型的機制,新的操作符decltype可以從一個表達式中“俘獲”其結果的類型并“返回”:
1. constvector<int>vi;
2. typedefdecltype(vi.begin())CIT;
3. CITanother_const_iterator;
三、統一的初始化語法
C++最少有 4種不同的初始化形式,如括號內初始化,見:
1. std::strings("hello");
2. intm=int();//defaultinitialization
還有等號形式的:
1. std::strings="hello";
2. intx=5;
對于 POD集合,又可以用大括號:
1. intarr[4]={0,1,2,3};
2. structtmtoday={0};
最后還有構造函數的成員初始化:
1. structS{
2. intx;
3. S():x(0){}};
這么多初始化形式,不僅菜鳥會搞得很頭大,高手也吃不消。更慘的是 C++03中居然不能初始化POD數組的類成員,也不能在使用 new[]的時候初始 POD數組!C++11就用大括號一統天下了:
1. classC
2. {
3. inta;
4. intb;
5. public:
6. C(inti,intj);
7. };
8. Cc{0,0};//C++11only.相當于Cc(0,0);
9. int*a=newint[3]{1,2,0};/C++11only
10. classX{
11. inta[4];
12. public:
13. X():a{1,2,3,4}{}//C++11,初始化數組成員
14. };
還有一大好事就是對于容器來說,終于可以擺脫push_back()調用了,C++11中可以直觀地初始化容器了:
1. //C++11containerinitializer
2. vectorvs<string>={"first","second","third"};
3. mapsingers=
4. {{"LadyGaga","+1(212)555-7890"},
5. {"BeyonceKnowles","+1(212)555-0987"}};
而類中的數據成員初始化也得到了支持:
1. classC
2. {
3. inta=7;//C++11only
4. public:
5. C();
6. };
四.deleted函數和 defaulted函數
像以下形式的函數:
1. structA
2. {
3. A()=default;//C++11
4. virtual~A()=default;//C++11
5. };
叫做 defaulted函數,=default;指示編譯器生成該函數的默認實現。這有兩個好處:一是讓程序員輕松了,少敲鍵盤,二是有更好的性能。
與 defaulted函數相對的就是 deleted函數:
1. intfunc()=delete;
這貨有一大用途就是實現 noncopyabe防止對象拷貝,要想禁止拷貝,用 =deleted聲明一下兩個關鍵的成員函數就可以了:
structNoCopy
{
NoCopy&operator=(constNoCopy&)=delete;
NoCopy(constNoCopy&)=delete;
};
NoCopya;
NoCopyb(a);//編譯錯誤,拷貝構造函數是deleted函數
nullptr
nullptr是一個新的 C++關鍵字,它是空指針常量,它是用來替代高風險的 NULL宏和 0字面量的。nullptr是強類型的:
voidf(int);//#1
voidf(char*);//#2
//C++03
f(0);//調用的是哪個f?
//C++11
f(nullptr)//毫無疑問,調用的是#2
所有跟指針有關的地方都可以用nullptr,包括函數指針和成員指針:
constchar*pc=str.c_str();//datapointers
if(pc!=nullptr)
cout<<pc<<endl;
int(A::*pmf)()=nullptr;//指向成員函數的指針
void(*pmf)()=nullptr;//指向函數的指針
委托構造函數
C++11中構造函數可以調用同一個類的另一個構造函數:
classM//C++11delegatingconstructors
{
intx,y;
char*p;
public:
M(intv):x(v),y(0),p(newchar[MAX]){}//#1target
M():M(0){cout<<"delegatingctor"<<end;}//#2delegating
#2就是所謂的委托構造函數,調用了真正的構造函數 #1。
右值引用
在 C++03中的引用類型是只綁定左值的,C++11引用一個新的引用類型叫右值引用類型,它是綁定到右值的,如臨時對象或字面量。
增加右值引用的主要原因是為了實現 move語義。與傳統的拷貝不同,move的意思是目標對象“竊取”原對象的資源,并將源置于“空”狀態。當拷貝一個對象時,其實代價昂貴且無必要,move操作就可以替代它。如在 string交換的時候,使用 move意義就有巨大的性能提升,如原方案是這樣的:
voidnaiveswap(string&a,string&b)
{
stringtemp=a;
a=b;
b=temp;
}
這種方案很傻很天真,很慢,因為需要申請內存,然后拷貝字符,而 move就只需要交換兩個數據成員,無須申請、釋放內存和拷貝字符數組:
voidmoveswapstr(string&empty,string&filled)
{
//pseudocode,butyougettheidea
size_tsz=empty.size();
constchar*p=empty.data();
//movefilled'sresourcestoempty
empty.setsize(filled.size());
empty.setdata(filled.data());
//filledbecomesempty
filled.setsize(sz);
filled.setdata(p);
}
要實現支持 move的類,需要聲明 move構造函數和 move賦值操作符,如下:
classMovable
{
Movable(Movable&&);//moveconstructor
Movable&&operator=(Movable&&);//moveassignmentoperator
};
C++11的標準庫廣泛使用 move語義,很多算法和容器都已經使用 move語義優化過了。
C++11的標準庫
除TR1包含的新容器(unordered_set,unordered_map, unordered_multiset,和unordered_multimap),還有一些新的庫,如正則表達式,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>
//C++11code
//arealloftheelementspositive?
all_of(first,first+n,ispositive());//false
//isthereatleastonepositiveelement?
any_of(first,first+n,ispositive());//true
//arenoneoftheelementspositive?
none_of(first,first+n,ispositive());//false
還有一個新的 copy_n:
#include<algorithm>
intsource[5]={0,12,34,50,80};
inttarget[5];
//從source拷貝5個元素到target
copy_n(source,5,target);
iota()算法可以用來創建遞增序列,它先把初值賦值給 *first,然后用前置 ++ 操作符增長初值并賦值到給下一個迭代器指向的元素,如下:
#include<numeric>
inta[5]={0};
charc[3]={0};
iota(a,a+5,10);//changesato{10,11,12,13,14}
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/
以及更加易于學習和使用。