• 文章
  • C++11 相較於 C++03 的改進
釋出
2011 年 9 月 30 日 (最後更新:2011 年 11 月 12 日)

C++11 相較於 C++03 的改進

評分:4.3/5 (430 票)
*****

關於 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 功能仍只有部分支援。