C++ STL array容器和普通陣列的比較

2020-07-16 10:05:21
和 C++ 普通陣列儲存資料的方式一樣,C++ 標準庫保證使用 array 容器儲存的所有元素一定會位於連續且相鄰的記憶體中,通過如下程式碼也可以驗證這一點:
#include <iostream>
#include <array>
using namespace std;
int main()
{
    array<int, 5>a{1,2,3};
    cout << &a[2] << " " << &a[0] + 2 << endl;
    return 0;
}
輸出結果為:

004FFD58 004FFD58

可以看到,a 容器中 &a[2] 和 &a[0] + 2 是相等的。因此在實際程式設計過程中,我們完全有理由去嘗試,在原本使用普通陣列的位置,改由 array 容器去實現。

用 array 容器替換普通陣列的好處是,array 模板類中已經封裝好了大量實用的方法,在提高開發效率的同時,程式碼的執行效率也會大幅提高。

舉個例子,我們完全可以使用 array 容器去儲存 char* 或 const char* 型別的字串:
#include <iostream>
#include <array>
using namespace std;
int main()
{
    array<char, 50>a{1,2,3};
    strcpy(&a[0], "http://c.biancheng.net/stl");
    printf("%s", &a[0]);
    return 0;
}
輸出結果為:

http://c.biancheng.net/stl

注意,array 容器的大小必須保證能夠容納複製進來的資料,而且如果是儲存字串的話,還要保證在儲存整個字串的同時,在其最後放置一個作為字串的結束符。此程式中,strcpy() 在拷貝字串的同時,會自動在最後新增

其實,程式碼中的 &a[0] 還可以用 array 模板類提供的 data() 成員函數來替換:
#include <iostream>
#include <array>
using namespace std;
int main()
{
    array<char, 50>a{1,2,3};
    strcpy(a.data(), "http://c.biancheng.net/stl");
    printf("%s", a.data());
    return 0;
}
此程式和上面程式的輸出結果完全相同。

注意,容器的疊代器和指標是不能混用的,即上面程式碼中不能用 a.begin() 來代替 &a[0] 或者 a.data[],這可能會引發錯誤。

文章前面提到,使用 array 容器代替普通陣列,最直接的好處就是 array 模板類中已經為我們寫好了很多實用的方法,可以大大提高我們編碼效率。例如,array 容器提供的 at() 成員函數,可以有效防止越界操縱陣列的情況;fill() 函數可以實現陣列的快速初始化;swap() 函數可以輕鬆實現兩個相同陣列(型別相同,大小相同)中元素的互換。
#include <iostream>
#include <array>
using namespace std;
int main()
{
    array<char, 50>addr1{"http://c.biancheng.net"};
    array<char, 50>addr2{ "http://c.biancheng.net/stl" };
    addr1.swap(addr2);
    printf("addr1 is:%sn", addr1.data());
    printf("addr2 is:%sn", addr2.data());
    return 0;
}
執行結果為:

addr1 is:http://c.biancheng.net/stl
addr2 is:http://c.biancheng.net


另外,當兩個 array 容器滿足大小相同並且儲存元素的型別相同時,兩個 array 容器可以直接直接做賦值操作,即將一個容器中的元素賦值給另一個容器。比如:
#include <iostream>
#include <array>
using namespace std;
int main()
{
    array<char, 50>addr1{ "http://c.biancheng.net" };
    array<char, 50>addr2{ "http://c.biancheng.net/stl" };
    addr1 = addr2;
    printf("%s", addr1.data());
    return 0;
}
執行結果為:

http://c.biancheng.net/stl


不僅如此,在滿足以上 2 個條件的基礎上,如果其儲存的元素也支援比較運算子,就可以用任何比較運算子直接比較兩個 array 容器。範例如下:
#include <iostream>
#include <array>
using namespace std;
int main()
{
    array<char, 50>addr1{ "http://c.biancheng.net" };
    array<char, 50>addr2{ "http://c.biancheng.net/stl" };
    if (addr1 == addr2) {
        std::cout << "addr1 == addr2" << std::endl;
    }
    if (addr1 < addr2) {
        std::cout << "addr1 < addr2" << std::endl;
    }
    if (addr1 > addr2) {
        std::cout << "addr1 > addr2" << std::endl;
    }
    return 0;
}
執行結果為:

addr1 < addr2

兩個容器比較大小的原理,和兩個字串比較大小是一樣的,即從頭開始,逐個取兩容器中的元素進行大小比較(根據 ASCII 碼表),直到遇到兩個不相同的元素,那個元素的值大,則該容器就大。

總之,讀者可以這樣認為,array 容器就是普通陣列的“升級版”,使用普通陣列能實現的,使用 array 容器都可以實現,而且無論是程式碼功能的實現效率,還是程式執行效率,都比普通陣列更高。