Оценка состояния в циклах? - PullRequest
3 голосов
/ 19 января 2009
string strLine;//not constant
int index = 0;
while(index < strLine.length()){//strLine is not modified};

сколько раз strLine.length() оценивается

нам нужно использовать nLength с nLength, назначенным strLine.length() непосредственно перед циклом

Ответы [ 9 ]

4 голосов
/ 19 января 2009

length будет оцениваться каждый раз, когда вы проходите через цикл, однако, поскольку length является постоянным временем (O(1)), это не имеет большого значения, и добавление переменной для хранения этого значения, вероятно, будет незначительным эффект с небольшим ударом по читабельности кода (а также разрывом кода, если строка когда-либо изменена).

3 голосов
/ 19 января 2009

length () определяется в заголовках, которые включены в ваш исходный файл, поэтому он может быть встроен компилятором, его внутренние вызовы также могут быть встроены, поэтому, если компилятор сможет обнаружить, что ваш экземпляр строки не изменился в цикле он может оптимизировать доступ к длине строки, поэтому он будет оцениваться только один раз. В любом случае, я не думаю, что сохранение значения длины строки действительно необходимо. Возможно, это поможет вам сэкономить некоторые наносекунды, но ваш код будет больше, и будет некоторый риск, когда вы решите изменить эту строку внутри цикла.

2 голосов
/ 19 января 2009

Я думаю, что в этом скрывается второй вопрос, и это "какая реализация более понятна?"

Если семантически вы подразумеваете, что длина strLine никогда не изменяется внутри тела цикла, сделайте это очевидным, назначив переменную с хорошо именованным значением. Я бы даже сделал это const. Это дает понять другим программистам (и вам самим), что значение сравнения никогда не меняется.

С другой стороны, это упрощает просмотр значения этого значения, когда вы проходите через код в отладчике. Hover-over работает намного лучше на локальном, чем на вызов функции.

Сказать: «оставь это как вызов функции; компилятор оптимизирует его», мне кажется преждевременной пессимизацией. Несмотря на то, что length () равен O (1), если он не встроен (вы не можете гарантировать, что оптимизации не отключены), это все же нетривиальный вызов функции. Используя локальную переменную, вы уточняете свое значение и получаете, возможно, нетривиальную оптимизацию производительности.

Делайте то, что делает ваши намерения наиболее ясными.

2 голосов
/ 19 января 2009

Каждый раз, когда это называется ... (каждый во время оценки). Если вы не меняете длину строки, вам лучше использовать временную переменную, такую ​​как:

string strLine;
int stringLength = strLine.length();
int index = 0;
while(index < stringLength);
1 голос
/ 20 января 2009

Как уже говорилось, поскольку функция string::length, скорее всего, полностью определена в заголовке и должна иметь значение O (1), почти наверняка оценят доступ к простому члену и вставят в ваш код. Поскольку вы не объявляете строку как volatile, компилятору разрешается представить, что никакой внешний код не собирается ее изменять, и оптимизировать вызов для доступа к одной памяти и оставить значение в регистре, если он обнаружит, что это хорошая идея.

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

1 голос
/ 19 января 2009

Если вы собираетесь использовать временную переменную, используйте спецификатор const, поэтому компилятор может добавлять оптимизации, зная, что значение не изменится:

string strLine;//not constant
int index = 0;
const int strLenght = strLine.Length();
while(index < strLine.length()){//strLine is not modified};

Скорее всего, сам по себе компилятор выполняет эти оптимизации при доступе к методу Length ().

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

int main()
{
    std::string strLine="hello world";

    for (int i=0; i < strLine.length(); ++i)
    {
        std::cout << strLine[i] <<std::endl;
    }
}

Создает эту сборку:

    for (int i=0; i < strLine.length(); ++i)
0040104A  cmp         dword ptr [esp+20h],esi 
0040104E  jbe         main+86h (401086h)

Но для этого кода

 std::string strLine="hello world";
 const int strLength = strLine.length();
 for (int i=0; i < strLength ; ++i)
 {
    std::cout << strLine[i] <<std::endl;
 }

генерирует это:

   for (int i=0; i < strLength ; ++i)
0040104F  cmp         edi,esi 
00401051  jle         main+87h (401087h) 

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

Пробовал с VSC ++ 2005

1 голос
/ 19 января 2009

strLine.length () будет оцениваться, тогда как (i

Сказав, что если строка постоянная, большинство компиляторов оптимизируют это (с правильными настройками).

0 голосов
/ 19 января 2009

Поскольку вы не меняете строку, не следует ли использовать

const string strLine;

Просто потому, что тогда компилятор получает больше информации о том, что может, а что не может измениться - хотя точно не знаю, насколько умным может быть компилятор C ++.

0 голосов
/ 19 января 2009

strLine.length() будет оцениваться каждый раз, когда вы проходите цикл.

Вы правы в том, что было бы более эффективно использовать nLength, особенно если strLine длинная.

...