Эффективно ли использование string.length () в цикле? - PullRequest
10 голосов
/ 27 февраля 2011

Например, если предположить, что string s это:

for(int x = 0; x < s.length(); x++)

лучше, чем это?

int length = s.length();
for(int x = 0; x < length; x++)

Спасибо, Джоэл

Ответы [ 6 ]

12 голосов
/ 27 февраля 2011

Как правило, следует избегать вызовов функций в условной части цикла, если результат не изменяется во время итерации.

Следовательно, каноническая форма:

for (std::size_t x = 0, length = s.length(); x != length; ++x);

Обратите внимание на 3 вещи:

  • Инициализация может инициализировать более одной переменной
  • Условие выражается с помощью != вместо <
  • Я использую pre-инкремент, а не постинкремент

(я также изменил тип, потому что отрицательная длина не имеет смысла, а интерфейс строки определен в терминах std::string::size_type, что обычно std::size_tв большинстве реализаций).

Хотя ... я признаю, что это не столько для производительности, сколько для читабельности:

  • Двойная инициализация означает, что и x, и lengthобласть действия настолько узка, насколько необходимо
  • За счет запоминания результата читатель не оставляет сомнений в том, может ли длина меняться во время итерации
  • Использование предварительного увеличения обычно лучше, когда вывам не нужно создавать временное со «старым» значением

Короче: используйте лучший инструмент для работы под рукой:)

4 голосов
/ 27 февраля 2011

Зависит от встроенных и оптимизационных возможностей компилятора. Как правило, второй вариант, скорее всего, будет быстрее (лучше: он будет быстрее или быстрее первого фрагмента, но почти никогда не будет медленнее).

Однако в большинстве случаев это не имеет значения, поэтому люди предпочитают первый вариант из-за его краткости.

3 голосов
/ 27 февраля 2011

Это зависит от вашей реализации / библиотеки C ++, единственный способ убедиться в этом - сравнить ее.Тем не менее, очевидно, что вторая версия никогда не будет медленнее первой, поэтому, если вы не измените строку в цикле, это разумная оптимизация.

1 голос
/ 05 сентября 2016

Хотя я не обязательно призываю вас сделать это, похоже, что быстрее звонить .length() быстрее, чем сохранять его в int, что удивительно (по крайней мере, на моем компьютере, учитывая, что я используюигровой ноутбук MSI с i5 4-го поколения, но на самом деле это не должно влиять на то, какой путь быстрее).

Тестовый код для постоянного вызова:

#include <iostream>

using namespace std;

int main()
{
    string g = "01234567890";
    for(unsigned int rep = 0; rep < 25; rep++)
    {
        g += g;
    }//for loop used to double the length 25 times.
    int a = 0;
    //int b = g.length();
    for(unsigned int rep = 0; rep < g.length(); rep++)
    {
        a++;
    }
    return a;
}

В среднем это составляет 385 мссогласно Code :: Blocks

И вот код, который хранит длину в переменной:

#include <iostream>

using namespace std;

int main()
{
    string g = "01234567890";
    for(unsigned int rep = 0; rep < 25; rep++)
    {
        g += g;
    }//for loop used to double the length 25 times.
    int a = 0;
    int b = g.length();
    for(unsigned int rep = 0; rep < b; rep++)
    {
        a++;
    }
    return a;
}

И это в среднем составляет около 420 мс.

Я уже знаю этот вопросесть принятый ответ, но практически не было проверенных ответов, поэтому я решил добавить свои 2 цента. У меня был такой же вопрос, как и у вас, но я не нашел здесь никаких полезных ответов, поэтому я запустил свой собственныйэксперимент.

1 голос
/ 27 февраля 2011

Насколько эффективным вы хотите быть?

Если вы не измените строку внутри цикла, компилятор легко увидит, что размер не изменится. Не усложняй это!

0 голосов
/ 27 февраля 2011

Является ли s.length () встроенным и возвращает переменную-член?тогда нет, в противном случае затраты на разыменование и помещение материала в стек, вы знаете все накладные расходы на вызов функции, которые вы будете нести за каждую итерацию.

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