關於 C++11
C++11,也稱為 C++0x,是 C++ 語言的新標準,於 2011 年底釋出。
它取代了 2003 年釋出的舊 C++03 標準。
當然,它帶來了對舊標準的改進,本文將概述其中一些。
重塑的 auto
關鍵字
冗長是壞的,主要是因為它使你的程式碼不那麼清晰。
因此,
auto
關鍵字,作為 C 的遺留物,在 C++11 中獲得了新的含義:自動型別推導。
示例
1 2 3 4 5 6
|
// the C++03 way
for (std::vector<int>::const_iterator ci = v.begin(); ci != v.end(); ++ci);
// the C++11 way
for (auto ci = v.cbegin(); ci != v.cend(); ++ci);
// notice the dedicated cbegin() and cend() member functions which return a const_iterator
|
糟糕的例子
1 2 3 4 5 6 7 8 9 10
|
auto x = 10.0;
// if a newbie programmer changes `10.0' to `10', x becomes an integral type
// and code depending on it to be a floating point type will fail
// advice 1: use auto against verbosity, not consistency
for (auto i = 0ul; i < v.size(); ++i);
// this is just a clever way of writing `unsigned long int i=0'
// advice 2: don't use auto if you specify the type, it defeats its purpose
// advice 1+2=3: don't use auto with constants
|
基於範圍的 for()
遍歷 STL 容器的內容是一項非常常見的操作。
C++11 現在提供了一個專門的
for()
,它可以遍歷任何具有
begin()
和
end()
成員函式,並且這些函式返回預期迭代器的物件。
它也可以用於普通的 C 陣列。
示例
1 2 3 4 5 6 7 8 9 10
|
// the C++03 way
for (std::vector<int>::iterator i = v.begin(); i != v.end(); ++i);
// the C++11 way
for (int &item: v);
// item will become, in order, all the things stored in v
// notice how we're referencing the item, that allows us to change it
for (const int &item: v); // can't change item, we reference it for speed
for (int item: v); // can't change item, we're passing it by value
|
初始化列表
C++03 中的容器不像經典的 C 風格陣列那樣可以“自然地”初始化。這種情況已經改變。
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
// C arrays
char array1[] = {'A', 'B'};
double array2[] = {32.0, 6.003, -0.1};
// C++03 vectors
std::vector<char> cpp03vector1;
cpp03vector1.push_back('A');
cpp03vector1.push_back('B');
std::vector<double> cpp03vector2(3);
cpp03vector2[0] = 32.0;
cpp03vector2[1] = 6.003;
cpp03vector2[2] = -0.1;
// C++11 vectors
std::vector<char> cpp11vector1 = {'A', 'B'};
std::vector<double> cpp11vector2 = {32.0, 6.003, -0.1};
// or...
std::vector<char> cpp11vector3{'A', 'B'};
std::vector<double> cpp11vector4{32.0, 6.003, -0.1};
// notice that this works for all other containers as well, not just std::vector
|
初始化列表也可以用於更復雜的結構。
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
#include <map>
#include <string>
#include <vector>
#include <utility>
using namespace std;
map<string, vector<pair<string, int>>> name_languages_year {
{"Dennis Ritchie", {{"B", 1969}, {"C", 1973}}},
{"Niklaus Wirth", {{"Pascal", 1970}, {"Modula-2", 1973}, {"Oberon", 1986}}},
{"Bjarne Stroustrup", {{"C++", 1983}}},
{"Walter Bright", {{"D", 1999}}}
};
// notice how the lists are nested to match the templates' parameters
cout << name_languages_year["Niklaus Wirth"].at(0).first << endl; // prints `Pascal'
// adds a new entry to the map
name_languages_year["John McCarthy"] = {
{"Lisp", 1958}
};
// notice the lack of explicit types
|
C++ 陣列
這更多的是一種補充而不是改進,但我還是決定把它包含在文章中。
C++11 提供了
std::array
,其目的是取代 C 陣列。它是動態大小的
std::vector
的一個固定大小的輕量級替代品。
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
#include <array>
// C arrays
char carray1[] = "Abc"; // caution, an unseen '\0' is added to the end
float carray2[] = {0.2f, 33.33f};
// C++ arrays
std::array<char, 3> cpparray1{{'A', 'b', 'c'}};
std::array<float, 2> cpparray2{{0.2f, 33.33f}};
// observation 1: the size must be deducible at compile time
// observation 2: the array cannot be resized
// observation 3: the inner braces are due to the nature of initializer lists,
// think of it as one list per template parameter
// array test drive: the old versus the new
std::cout << sizeof carray1 - 1; // -1 because of the extra '\0'
std::cout << sizeof carray2 / sizeof (float); // because number of elements != number of bytes
std::cout << cpparray1.size();
std::cout << cpparray2.size();
carray2[-5] = 0.1f; // do the moonwalk!
cpparray2.at(-5) = 0.1f; // throws std::out_of_range exception
// of course there are more reasons why C++ arrays are better than C arrays
// but this example code section is already too big...
|
小的修正
C++03 有一堆小錯誤和設計缺陷,這些在 C++11 中得到了修復。
- 諸如
set<vector<int>>
之類的東西終於可以編譯了。
請注意最後兩個尖括號之間的空格缺失。
std::string
現在具有 front()
和 back()
成員函式。
- 檔案流現在可以接受
std::string
作為檔名。
這意味著可以減少對那個可笑的 c_str()
成員函式的使用。
- 現在可以透過使用過載函式輕鬆地將數值轉換為
std::string
string to_string(int)
string to_string(float)
string to_string(double)
...
C++11 的編譯器支援
……
情況還不錯。但還需要一兩年時間來穩定。
GNU C++ 編譯器需要命令列引數
-std=c++0x 來編譯 C++11 程式碼。
Microsoft Visual Studio 2010 對 C++11 功能有部分支援,開箱即用。
Microsoft Visual Studio 201x (v11) 對 C++11 功能仍只有部分支援。