一點點開始熟悉C++11的新特性

  C++11標準由C++標準委員會於2011年8月12日公佈,並於2011年9月出版。雖然長期在使用C++,但是對C++11一直處於觀望,處於很難用起來(編譯器支持等問題),沒有很大興趣去學會的狀態。也許風向變到C++11成爲主流,纔會引起大家的重視和追捧。可是這是常人思維,基本上週圍的精英牛人都已經掌握了這些東西,並且已經開始用於工作當中了。 所以這就是我這樣的常人和牛人的巨大差別。所以我也要跟上節奏,稍稍學習一下。

auto

C++11中引入auto的作用是爲了自動類型推導,將顯而易見的類型設定交給編譯器來做,這將簡化我們的編程工作。而且編譯器本來也要計算右邊值的類型是否和左邊匹配,所以這種自動推導並不會對效率產生不良影響。

auto a;  //錯誤,完全無法推導類型 
auto i = 5;  
auto d = 6.2;  
auto str = "Hello World";  
auto ch = 'x';  
auto func = less<int>();  //函數指針
vector<int> iv;  
auto ite = iv.begin();  //長長枚舉類型不用寫了
auto p = new foo() // 對自定義類型進行類型推導 

更高級的用法:

template <typename Product, typename Creator>  
void processProduct(const Creator& creator) {  
    Product* val = creator.makeObject();  
    // do somthing with val  
}         

可以藉助auto簡化模板參數

template <typename Creator>  
void processProduct(const Creator& creator) {  
    auto val = creator.makeObject();  
    // do somthing with val  
} 

decltype

新的操作符 decltype 可以從一個表達式中“俘獲”其結果的類型並“返回”

const vector<int> vi;  
typedef decltype (vi.begin()) CIT;  
CIT another_const_iterator;  //CIT等效vector<int>::iterator

lambda

lambda說簡單了就是一個簡單的匿名函數,可以靈活混跡於代碼當中,不用規規矩矩的聲明函數寫實現。在C++中它的使用格式是:
capture->return-type {body} 其中capture是lambda表達式可以取得的外部變量,paramters是傳入參數,->指向返回值類型,body表達式即函數體。

vector<int> iv{5, 4, 3, 2, 1};  
int a = 2, b = 1;  
for_each(iv.begin(), iv.end(), [b](int &x){cout<<(x + b)<<endl;});
for_each(iv.begin(), iv.end(), [=](int &x){x *= (a + b);});
for_each(iv.begin(), iv.end(), [=](int &x)->int{return x * (a + b);});

[=]中間的等號代表lambda表達式可以用所有的外部變量。

nullptr

nullptr 是一個新的 C++ 關鍵字,它是空指針常量,它是用來替代高風險的 NULL 宏和 0 字面量的。nullptr 是強類型的:

void f(int); //#1  
void f(char *);//#2  
//C++03  
f(0); //調用的是哪個 f?  甚至還有explicit來專門處理這個問題
//C++11  
f(nullptr) //毫無疑問,調用的是 #2  

deleted 和 defaulted 函數

struct A  
{  
 A()=default; //C++11  
 virtual ~A()=default; //C++11  
};  

=default; 指示編譯器生成該函數的默認實現。這有兩個好處:一是讓程序員輕鬆了,少敲鍵盤,二是有更好的性能。
與 defaulted 函數相對的就是 deleted 函數,它代表函數刪除掉了,如果使用就報錯。如下例,用於阻止拷貝:

struct NoCopy  
{  
    NoCopy & operator =( const NoCopy & ) = delete;  
    NoCopy ( const NoCopy & ) = delete;  
};  
NoCopy a;  
NoCopy b(a); //編譯錯誤,拷貝構造函數是 deleted 函數  

優雅的初始化方法

在引入C++11之前,只有數組能使用初始化列表,其他容器想要使用初始化列表,只能用以下方法:

int arr[3] = {1, 2, 3}  
vector<int> v(arr, arr + 3); 

在C++11中,我們可以使用以下語法來進行替換:

int arr[3]{1, 2, 3};  
vector<int> iv{1, 2, 3};  
map<int, string>{{1, "a"}, {2, "b"}};  
string str{"Hello World"}; 

委託構造(代理構造)函數

C++11 中構造函數可以調用同一個類的另一個構造函數:

class M //C++11 delegating constructors  
{  
 int x, y;  
 char *p;  
public:  
 M(int v) : x(v), y(0),  p(new char [MAX])  {} //#1 target  
 M(): M(0) {cout<<"delegating ctor"<<end;} //#2 delegating  
}

記得曾今用過類似的方式,不過直到今天突然迷糊了,不知道當時是用失敗了,還是編譯器套用了C++11特性才編譯通過的。至少說明這是比較有用的新特性。

右值引用

在 C++03 中的引用類型是隻綁定左值的,C++11 引用一個新的引用類型叫右值引用類型,它是綁定到右值的,如臨時對象或字面量。增加右值引用的主要原因是爲了實現 move 語義。與傳統的拷貝不同,move 的意思是目標對象“竊取”原對象的資源,並將源置於“空”狀態。當拷貝一個對象時,其實代價昂貴且無必要,move 操作就可以替代它。如在 string 交換的時候,使用 move 意義就有巨大的性能提升,如原方案是這樣的:

void naiveswap(string &a, string & b)  
{  
 string temp = a;  
 a=b;  
 b=temp;  
}  

這種方案很傻很天真,很慢,因爲需要申請內存,然後拷貝字符,而 move 就只需要交換兩個數據成員,無須申請、釋放內存和拷貝字符數組:

void moveswapstr(string& empty, string & filled)  
{  
//pseudo code, but you get the idea  
 size_t sz=empty.size();  
 const char *p= empty.data();  
//move filled's resources to empty  
 empty.setsize(filled.size());  
 empty.setdata(filled.data());  
//filled becomes empty  
 filled.setsize(sz);  
 filled.setdata(p);  
}  

要實現支持 move 的類,需要聲明 move 構造函數和 move 賦值操作符,如下:

class Movable  
{  
Movable (Movable&&); //move constructor  
Movable&& operator=(Movable&&); //move assignment operator  
};  

C++11 的標準庫廣泛使用 move 語義,很多算法和容器都已經使用 move 語義優化過了。
這一段沒看太明白,不過像QT這樣的庫,幾乎把所有對象都實現成了這種“淺拷貝”方式避免簡單交換產生的不必要性能消耗。


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++11 code  
//are all of the elements positive?  
all_of(first, first+n, ispositive()); //false  
//is there at least one positive element?  
any_of(first, first+n, ispositive());//true  
// are none of the elements positive?  
none_of(first, first+n, ispositive()); //false  

還有一個新的 copy_n:

#include <algorithm>  
int source[5]={0,12,34,50,80};  
int target[5];  
//從 source 拷貝 5 個元素到 target  
copy_n(source,5,target);  

iota() 算法可以用來創建遞增序列,它先把初值賦值給 *first,然後用前置 ++ 操作符增長初值並賦值到給下一個迭代器指向的元素,如下:

#include <numeric>  
int a[5]={0};  
char c[3]={0};  
iota(a, a+5, 10); //changes a to {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/)以及更加易於學習和使用。
如果覺得 C++ 變化太大了,不必驚恐,花點時間來學習就好了。可能在你融會貫通新特性以後,你會同意 Stroustrup 的觀點:C++11 是一門新的語言——一個更好的 C++。


外部資料:
  30分鐘瞭解C++11新特性
  C++11中值得關注的幾大變化
  開始使用C++11的9個理由
  C++11各編譯器支持情況對比
  百度百科C++11
  微軟官方關於現代C++(C++11)的詳細資料

發佈了24 篇原創文章 · 獲贊 7 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章