C++11已不是新鮮技術,但對於我來說,工作中用得還不夠多(前東家長時間使用gcc3.4.5,雖然去年升了4.8.2,但舊模塊維護還是3.4.5居多;新東家用的是4.4.6,不能完整支持C++11,而且有內部有基礎庫早已支持了C++11 STL的部分功能),再加上自己的練習也寫得少,了解僅是幾點簡單的皮毛,
這里對C++11學習總結一番,期望對他人以及未來的我有點技術知識索引上的幫助。
首先,wiki是最全面的:
https://en.wikipedia.org/wiki/C%2B%2B11,這是C++完整的新功能,個人使用的編譯器可能不完整支持,可以看這個編譯器+版本對C++1X的支持情況:
http://en.cppreference.com/w/cpp/compiler_support 。
然后,看英文不夠快,找一篇看起來比較全的中文總結(不全,還是要看wiki):
http://www.cnblogs.com/pzhfei/archive/2013/03/02/CPP_new_feature.html 。
一、新特性簡介
C++11之前被稱為C++0x,因為原本計划在2010年發布,所以之前一些編譯器使用C++11的編譯參數是:-std=c++0x,后面使用:-std=c++11。C++11 設計的核心是:少改動語言,多改動基礎庫。
改動涉及到這幾點:支持多線程編程(增加了thread庫)、加強泛型編程(增加了hash容器、任意多個元素的tuple、bind函數、lambda函數)、統一初始化(以花括號調用構造函數)、性能(右值引用和move),其它stl庫(正則表達式、原子操作庫),另外還有一些語法糖的支持,如:default、delete定義(可以在派生類中delete掉基類的public函數),裸字符串的定義、類非靜態成員變量直接賦值、nullptr、支持連續兩個右尖括號、后置返回類型、Range-based的for循環、構造函數可以調用另一個構造函數、override關鍵字用於發現虛函數的覆蓋錯誤、string literal.......。
二、部分常用新特性\庫
挑選幾個常用的記錄如下
1、統一初始化
之前,我想初始化一個放着map對象的容器,需要這樣子:
std::vector<std::map<std::string, std::string> > a; std::map<std::string, std::string> tmp; tmp.insert(std::make_pair("1", "2")); a.push_back(tmp);
現在,我可以直接用大括號:
std::vector<std::map<std::string, std::string>> a{ { { "1", "2" } } }
注: 部分統一初始化要到gcc4.7之后才支持。
2、函數綁定和lambda
函數綁定是基礎庫支持的,把一個函數轉換為一個對象,在異步編程上用的很多(回調函數bind成一個對象,然后把對象交給異步工作完成的通知者,由它觸發異步回調調用)。
lambda語法,則可以跟標准庫的算法配合使用,或者跟bind一起用在異步編程上。
eg1: bind
class Work { public: void do_work() { std::cout << "do work" << std::endl; } }; int main() { Work work; auto bar = std::bind(&Work::do_work, &work); bar(); }
eg2:清除字符串中的'a'字符:
std::string tmp = "abcdefgdaaa"; tmp.erase(std::remove_if(tmp.begin(), tmp.end(), [](char x) { return x == 'a'; }), tmp.end()); std::cout << tmp << std::endl;
lambda語法:
[capture](parameters)->return-type->{body}
[capture](parameters){body}
[] // 沒有定義任何變量。使用未定義變量會導致錯誤。
[x, &y] // x 以傳值方式傳入(默認),y 以引用方式傳入。
[&] // 任何被使用到的外部變量皆隱式地以引用方式加以使用。
[=] // 任何被使用到的外部變量皆隱式地以傳值方式加以使用。
[&, x] // x 顯示地以傳值方式加以使用。其余變量以引用方式加以使用。
[=, &z] // z 顯示地以引用方式加以使用。其余變量以傳值方式加以使用。
注:lambda需要gcc4.5之后才支持
3、直接給類成員變量設置默認值
Non-static data member initializers
eg:
class A { public: A () {} explicit A(int new_value) : value(new_value) {} int get() { return value; } private: int value = 5; // 支持直接寫默認值 };
注:至少需要gcc4.7
4、新增tuple類型
tuple類型在傳輸多種類型組成的數據時,可以省去定義struct,而且可以有任意多的成員。
eg:
std::tuple<std::string, std::string, std::string, int, int> record = std::make_tuple("a", "b", "c", 100, 200); std::cout << std::get<0>(record) << std::endl; std::cout << std::get<4>(record) << std::endl;
gcc4.4對tuple的支持不夠完整(不用使用const 字符賦值給string),需要gcc4.7以上才完善。
5、新增hash表
std::unordered_set
std::unordered_multiset
std::unordered_map
std::unordered_multimap
查找性能比set、map的要快。
6、新增多線程支持
std::thread
std::async
std::promise,std::future,
要特別說明下promise、future的概念:
“主線程創建一個promise,將與promise關聯的future交給新的線程,新線程等待從promise獲取數據,主線程通過promise向期望設置值,新線程收到通知繼續往下走。”
這說明,promise/future是用於異步編程時,線程之間的同步的,有點像多線程編程下的event通知。
eg:
#include <iostream> #include <functional> #include <thread> #include <future> void show(std::future<int>& fut) { std::cout << "work thread:" << std::this_thread::get_id() << std::endl; int x = fut.get(); // 等待獲取到結果 std::cout << x << std::endl; } int main(){ std::cout << "main thread:" << std::this_thread::get_id() << std::endl; std::promise<int> promise; std::future<int> future = promise.get_future(); std::thread work_thread(show, std::ref(future)); std::this_thread::sleep_for(std::chrono::seconds(3)); promise.set_value(10); work_thread.join(); return 0; }
注:promise/future至少需要gcc4.7才支持
擴展說明: 從上面的例子可以看到,標准庫的promise/future不支持設置回調函數,需要自己通過get函數等待,這是異步調用者(主線程)主動的在等待通知,不像js可以通過.then函數設置回調通知函數,調用者可以被動的被調用。
所以,當前不能做到徹底的異步編程(一個回調后面繼續跟着回調)。但.then 函數已經在規划中,參見:
"With .then, instead of waiting for the result, a continuation is “attached” to the asynchronous operation, which is invoked when the result is ready. "
"do this, and when it is done, then do this, and when it is done, then do this..."
有then函數的好處是,我們的代碼可以實現徹底的異步,以上面的例子為例,我只要告訴future回調函數是xx,主線程就不用再等待,它可以去做別的,當工作完成的時候,工作線程主動的去觸發回調函數xx的調用。
另外,boost已經有then的功能,
#include <iostream> #include <string> #define BOOST_THREAD_PROVIDES_FUTURE #define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION #include <boost/thread/future.hpp> using namespace boost; int main() { future<int> f1 = async([]() { return 123; }); future<std::string> f2 = f1.then([](future<int> f) { std::cout << f.get() << std::endl; // here .get() won't block return std::string("sgfsdfs"); }); }
部分公司使用boost,或者從boost里借鑒future.then()的實現造了一個基礎庫,就可以在代碼中實現 : do this, and when it is done, then do this, and when it is done, then do this ....
7、其它
(1)可以定義一個無需轉義的字符串,如:std::string b = R"x(c:\abc)" yy l)x";
其中x(是一個標識符,x可以任意,最長16個字符。
注意:Raw string literals至少需要gcc4.4
(2)正則表達式庫
(3)構造函數委托
(4)std::shared_ptr 智能指針
(5)railing-return-type 后置返回類型
本文所在:http://www.cnblogs.com/cswuyg/p/6220671.html
學習參考: