Является ли for-l oop или итератор более быстрым способом прохождения строки? - PullRequest
0 голосов
/ 29 апреля 2020

У меня есть строка.

std::string strLine;

Я могу пройти строковые символы, используя if l oop

for (int i = 0; strLine[i]; i++)

Другой способ, который я могу сделать, - использовать итератор строки

string::iterator it;
for (it = strLine.begin(); it < strLine.end(); it++) 

Какой более быстрый и гибкий способ итерации?

Ответы [ 2 ]

4 голосов
/ 29 апреля 2020

Есть некоторые проблемы с примерами циклов, которые вы показали. Вот несколько распространенных способов перебора строки:

// index based loop
for (auto i = 0u; i < strLine.size(); ++i)
  cout << strLine[i];

// iterator based loop
for (auto i = strLine.begin(); i != strLine.end(); ++i)
  cout << *i;

// range-for loop
for (auto &c: s)
  cout << c;

Все эти версии имеют одинаковую производительность, поскольку компилятор будет генерировать в основном один и тот же код для всех них.

Вдохновлен @ Ответ farassalem с тестом, я добавил следующие строки перед запуском тех же тестов:

cout << "warming up for tests ...\n";
cout << strLine << endl;
cout << "warmed up for tests ...\n";

и вы получите практически одинаковую производительность для всех 3 версий:

warming up for tests ...
This is a string!
warmed up for tests ...
This is a string!
index-based loop CPU time: 0.003 ms
index-based loop real time: 0.003264 ms
This is a string!
iterator-based loop CPU time: 0.003 ms
iterator-based loop real time: 0.003131 ms
This is a string!
range-for based loop CPU time: 0.002 ms
range-for based loop real time: 0.002728 ms

Вы все равно должны обратите пристальное внимание на как вы оцениваете, прежде чем воспринимать результаты слишком серьезно.

2 голосов
/ 29 апреля 2020

Проверьте этот код, печатая строку This is a string!: LIVE

    cpu_time_start = clock();
    real_time_start = chrono::high_resolution_clock::now();

    for (auto i = 0u; i < strLine.size(); ++i)
        cout << strLine[i];
    cout << endl;

    cpu_time_end = clock();
    real_time_end = chrono::high_resolution_clock::now();
    cout << "index-based loop CPU time: " << 1000.0 * (cpu_time_end-cpu_time_start) / CLOCKS_PER_SEC << " ms\n"
         << "index-based loop real time: "<< chrono::duration<double, milli>(real_time_end-real_time_start).count() << " ms\n";

    //---------------------------------------------------------------------

    // get start time, same as above 
    for (auto i = strLine.begin(); i != strLine.end(); ++i)
        cout << *i;
    cout << endl;
    // get end time and print 

    //---------------------------------------------------------------------

    // get start time, same as above
    for (auto &c: strLine)
        cout << c;
    cout << endl;
    // get end time and print 

РЕДАКТИРОВАТЬ:

Благодаря @ cigien, он указал на более точный способ сравнительного анализа путем прогрева. Кажется, что они немного похожи друг на друга по производительности с точки зрения времени выполнения, и если вы измените порядок циклов в коде, похоже, что любой из них может быть немного быстрее другого, я думаю, это связано с кэшированием, но все же я не думаю, что компилятор выдаст для них один и тот же код. Вы можете разогреться, просто распечатав строку перед печатью итерацией. И, возможно, более точный способ сравнить их - проверить каждое l oop в одной программе отдельно.

Это вывод при компиляции с g++ -Wall -std=c++17 -O2.

warming up for tests ...
This is a string!
warmed up for tests ...
This is a string!
index-based loop CPU time: 0.008 ms
index-based loop real time: 0.005986 ms
This is a string!
iterator-based loop CPU time: 0.004 ms
iterator-based loop real time: 0.003417 ms
This is a string!
range-for based loop CPU time: 0.003 ms
range-for based loop real time: 0.002755 ms

Я оставлю эту часть СТАРЫЙ ОТВЕТ , чтобы люди знали, что произошло:

СТАРЫЙ ВЫХОД!

This is a string!
index-based loop CPU time: 0.054 ms
index-based loop real time: 0.054416 ms
This is a string!
iterator-based loop CPU time: 0.005 ms
iterator-based loop real time: 0.004291 ms
This is a string!
range-for based loop CPU time: 0.004 ms
range-for based loop real time: 0.004308 ms

Похоже, что range-for loop и iterator-based loop очень близки по производительности с точки зрения времени выполнения и оба выполняются примерно на 10x быстрее, чем index-based loop. Попробуйте строки большей длины для получения более точных результатов, запустите его много раз и получите среднее значение.

Вы также можете попробовать скомпилировать его в Compiler Explorer , я не думаю, что тот же код будет генерироваться.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...