std::vectorのfillコンストラクタをどんどん使おう

やあ子どもたち。元気にしてたかな。今日はstd::vectorの初期構築方法とそのパフォーマンスについて考えるよ。
25万要素の vector< int >で、しかもその中身が全て71で初期化されているものを用意することを考えよう。この場合は、vector< int > を、サイズ指定で初期化して、std::fillで、71という値で埋めていけばいいやと考えてしまいがちなのだが、どうやらそれは間違いのようだよ。
では早速以下コードを見てみよう。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main(int argc, const char * argv[])
{
    const int num = 250000;
    auto t0 = clock();
    // トライその1
    {
        vector< int > vec_a( num );
        fill( vec_a.begin(), vec_a.end(), 71 );
        for( int i=0; i<20; ++i )
            cout << vec_a[i] <<", ";
        cout << ",,,"<< endl;
        cout << clock() - t0 << " clocks"<<endl;
        cout << "size of vec_a=" << vec_a.size() << endl;
    }
    t0 = clock();
    // トライその2
    {
        vector< int > vec_b( num, 71 );//←ここがfillコンストラクタ
        for( int i=0; i<20; ++i )
            cout << vec_b[i] <<", ";
        cout << ",,,"<< endl;
        cout << clock() - t0 << " clocks"<<endl;
        cout << "size of vec_b=" << vec_b.size() << endl;
    }   
    return 0;
}

そして出力結果は以下のようになったよ。

71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, ,,,
5377 clocks
size of vec_a=250000
71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, ,,,
735 clocks // ← 速ーーーーッ!!
size of vec_b=250000

いかがだろうか。トライ2の方ではstd::vector の初期化に、「サイズ、値」を受け取る、「fillコンストラクタ」を利用していて、トライその1よりも実に5倍以上も速いという結果が出たよ。両者順番を入れ替えると若干このパフォーマンス比の割合は変わってくるけど、それでもトライ2の方が3倍高速という結果が出た。もちろん実装系によってこの開き具合には差が出ると思う。今回は、XCode 4.6 を使っての実験結果でした。
というわけで、std::vectorが高速なのはわかっていたが、サイズ・内容値一律指定の初期化では、どんどんfillコンストラクタを使おう、ぜひともfillコンストラクタを使うべき、ということが言えそうだ。これもあまり言及されてない事実みたいなので今回緊急起稿してみたぞ。
チャオ!