說一說vector


vector<T>標准庫模版類應該是絕大多數c++程序員使用頻率比較高的一個類了。不過vector<bool>也許就不那么被程序員所了解。關於vector<bool>不嘗試研究一番,一般還不太容易知道其中蘊含的問題。

首先得明確一點,那就是vector<bool>是vector<T>的特化版。這個特化版本要解決的問題就是存儲容量的問題。

To optimize space allocation, a specialization of vector for bool elements is provided.

所以,它一般來說是以位的方式來存儲bool的值。從這里我們可以看出,如果使用位來提升空間效率可能引出的問題就是時間效率了。因為俺們的計算機地址是以字節為單位的。這里可以看一個例子:

int main()
{
    clock_t t1, t2, t3;
    vector<bool> vb;
    vector<int> vi;
    vector<char> vc;

    t1 = clock();
    for (int i = 0; i < 1000; ++i)
    {
        for (int j = 0; j < 1000; ++j)
        {
            vb.push_back(true);
        }
    }
    t1 = clock() - t1;

    t2 = clock();
    for (int i = 0; i < 1000; ++i)
    {
        for (int j = 0; j < 1000; ++j)
        {
            vi.push_back(1);
        }
    }
    t2 = clock() - t2;

    t3 = clock();
    for (int i = 0; i < 1000; ++i)
    {
        for (int j = 0; j < 1000; ++j)
        {
            vc.push_back('a');
        }
    }
    t3 = clock() - t3;

    cout << "'vector<bool>::push_back(true)' 1000000 times cost: " << t1 << endl;
    cout << "'vector<int>::push_back(1)' 1000000 times cost: " << t2 << endl;
    cout << "'vector<char>::push_back('a')' 1000000 times cost: " << t3 << endl;

    t1 = clock();
    for (int i = 0; i < 1000; ++i)
    {
        for (int j = 0; j < 1000; ++j)
        {
            bool b = vb[j + 1000 * i];
        }
    }
    t1 = clock() - t1;

    t2 = clock();
    for (int i = 0; i < 1000; ++i)
    {
        for (int j = 0; j < 1000; ++j)
        {
            int b = vi[j + 1000 * i];
        }
    }
    t2 = clock() - t2;

    t3 = clock();
    for (int i = 0; i < 1000; ++i)
    {
        for (int j = 0; j < 1000; ++j)
        {
            char b = vc[j + 1000 * i];
        }
    }
    t3 = clock() - t3;

    cout << "'vector<bool>::operator[]' 1000000 times cost: " << t1 << endl;
    cout << "'vector<int>::operator[]' 1000000 times cost: " << t2 << endl;
    cout << "'vector<char>::operator[]' 1000000 times cost: " << t3 << endl;

    return 0;
}

我的機器上的輸出結果是:

vectorbool

vector<bool>的耗時要比vector<T>多至少40倍以上!不簡單。。。

這里我們只是簡單得驗證了下vector<bool>的特別之處。接下來再從標准文檔中看看有什么特別之處:

There is no requirement that the data be stored as a contiguous allocation of bool values. A space-optimized representation of bits is recommended instead.

所以,vector<bool>就沒要求說底層的存儲必須是連續的空間。這也就從一個方面說明了我們上面的例子有如此之大的差異一個原因。

另外,事實上vetor<bool>只是從暴露出來的API上看,是一個容器。而事實上他丫的就不是個容器。

這還得先簡單說說C++的容器。我們知道vector<T>(T不是bool)是一個順序容器(Sequence container)。因此他滿足C++標准中關於容器的標准。比方說下面這條:

Expression Return type
X::reference lvalue of T

簡單說vector<int>::reference至少必須是一個int。而vector<bool>則不是這樣的。vector<bool>::reference是一個可以和bool兼容的代理數據結構。

最簡單的驗證這一點的例子就是:

template <typename T>
void func(vector<T>& v)
{
    T& ref = v[0];
}

上面這段代碼你在vc2012或者g++4.6.1上,傳遞一個vector<bool>對象,都不能通過編譯。g++給出的編譯錯誤就相當清晰了:

vectorbool.cpp: In function ‘void func(std::vector<T>&) [with T = bool']’:

vectorbool.cpp:18:11:    instantiated from here

vectorbool.cpp:9:17: error: invalid initialization of non-const reference of type ’bool&’ from an rvalue of type ‘std::vector<bool>::reference {aka std::_Bit_reference}’

operator[]返回的reference是一個右值就不是個左值(lvalue of T)。

所以,vector<bool>就不是個容器。

總結一下:

  1. vector<bool>可能存在性能問題
  2. 它並不是個真正的容器,因此在模版代碼上的使用可能會有問題。如果問題能發生在編譯器那還好,換到運行期,還真有點麻煩(vector<bool>::operator[] misbehavior?)。

Reference:

  1. What You Should Know about vector<bool>
  2. The Fate of vector<bool> in C++09
  3. vector<bool>: More Problems, Better Solutions

 

更新(2017年3月27日)

vector<bool>因為其特殊性,所以在使用Range-based for loop時,要小心。比方說:

 1 int main()
 2 {
 3   std::vector<bool> bools { false, false, false }
 4 
 5   // change value (expected to see bools are not changed).
 6   for (auto b : bools)
 7   {
 8     b = true;
 9   }
10 
11   // print bools
12   for (auto const & b : bools)
13   {
14     std::cout << std::boolalpha << b << std::endl;
15   }
16 
17   return 0;
18 }

我們會發現bools里的value全部變成true了。真是頭大。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM