0

std :: vectorのように、コンテナを反復処理する方法を学んだことから、次のようにイテレータを使用することができます。

for(vector<int>::iterator it = numbers.begin(); it != numbers.end(); it++)

私の質問は、standatdを使用してコンテナーを反復処理しないのはなぜですか。関数を、、およびforとして呼び出す必要がないため、より高速です。 私が試したところ、イテレータを使用するよりもX30を使用する方が高速であることがわかりました。 私はこのコードを書きました: numbers.begin()numbers.end()
for

vector<int> numbers;
for (int i = 0; i < 5000000; i++)
{
    numbers.push_back(i);
}

time_t t = time(0);
struct tm * now = localtime(&t);
cout << now->tm_hour << ":" << now->tm_min << ":" <<  now->tm_sec << "\n";

for(vector<int>::iterator it = numbers.begin(); it != numbers.end(); it++)
{
    *it = 7;
}

t = time(0);
now = localtime(&t);
cout << now->tm_hour << ":" << now->tm_min << ":" <<  now->tm_sec << "\n";

int size = numbers.size();
for (int i = 0; i < size; i++)
{
    numbers[i] = i;
}

t = time(0);
now = localtime(&t);
cout << now->tm_hour << ":" << now->tm_min << ":" <<  now->tm_sec;

出力は次のとおりです。

    19:28:25
    19:28:56
    19:28:57
4

2 に答える 2

2

あなたの数を見てください-30秒で単純なベクトルを繰り返しますか?それはCPU時間の永遠です。そこに何か問題があります。

いくつかの提案:

  • ベクトルは約19MBかかります。それほど多くはありませんが、他の多くのアプリがコンピューターにロードされている場合は、ヒープの断片化やVMのスワッピングが発生する可能性があります。信頼できる数を取得するには、できるだけ多くのアプリを閉じて、システムがアイドル状態であることを確認してください。

  • coutはタイマー内にあるため、iostreamライブラリの一部のパフォーマンスを測定しています。停止時間を取った、時間指定セクションの外でカウトを行います。

  • 1秒のクロックは、パフォーマンスメトリックに対して十分に正確ではありません。timevalとgettimeofday()を使用して、マイクロ秒の精度を取得します。

  • ベクトルを1回繰り返すだけで、実行間に大きな違いが見られました。より再現性の高い結果を得るには、ベクトルを複数回(500回など)繰り返します。(これは、スワッピング/フラグメンテーションの問題を引き起こす可能性がある、より大きなベクトルを使用するよりも優れています。)

  • 最適化をオンにします(例:g ++ -O3)。ループははるかに高速に実行され、時間差ははるかに小さくなります。インライン最適化は、おそらくstd ::vector<>コードをさらに支援します。

これらの変更(以下)により、私のコンピューターでは、イテレーターは最適化なしのインデックスより4倍遅くなりましたが、-O1の場合はわずかに速く、-O3の場合はほとんど同じでした。

#include <iostream>
#include <sys/time.h>
#include <vector>
using namespace std;

const unsigned N_REPS = 500;
const unsigned N_ITEMS = 5000000;

int print_elapsed(timeval start)
{
    timeval stop;
    gettimeofday(&stop, NULL);
    int elapsed = (stop.tv_sec * 1000000 + stop.tv_usec) - (start.tv_sec * 1000000 + start.tv_usec);
    cout << elapsed << "us" << endl;
    return elapsed;
}

int main()
{
    vector<int> numbers;
    numbers.reserve(N_ITEMS); // avoid heap fragmentation
    for (int i = 0; i < N_ITEMS; ++i)
        numbers.push_back(i);

    timeval start;
    gettimeofday(&start, NULL);

    for (unsigned r = 0; r < N_REPS; ++r)
        for (vector<int>::iterator it = numbers.begin(); it != numbers.end(); ++it)
            *it = r;

    int elapsed0 = print_elapsed(start);
    gettimeofday(&start, NULL);

    unsigned size = numbers.size();
    for (unsigned r = 0; r < N_REPS; ++r)
        for (unsigned i = 0; i < size; ++i)
            numbers[i] = r;

    int elapsed1 = print_elapsed(start);
    cout << 100 * float(elapsed1) / elapsed0 << '%' << endl;

    return 0;
}
于 2013-02-23T19:46:37.747 に答える
1

イテレータを使用すると、コンテナタイプを別のタイプに変更しても、反復コードは同じままであるという柔軟性が得られます。これは、すべての標準ライブラリコンテナがイテレータを提供するためです。ある意味で、より一般的なコードを書く機会を与えてくれます。

于 2013-02-23T19:26:15.070 に答える