Нужна ли верхняя граница цикла для сохранения в дополнительной переменной?

Я часто вижу это в старом коде

DWORD num = someOldListImplementation.GetNum();
for (DWORD i = 0; i < num; i++)
{
someOldListImplementation.Get(i);
}

скорее, чем

   for (DWORD i = 0; i < someOldListImplementation.GetNum(); i++)
{
someOldListImplementation.Get(i);
}

Я думаю, что первая реализация должна предотвращать вызовы GetNum() на каждом цикле. Но есть ли случаи, когда компилятор в C ++ 11 выполняет некоторую оптимизацию для второго фрагмента кода, который делает num переменная устарела?

Должен ли я всегда отдавать предпочтение первой реализации?

Если этот вопрос дублирует другой вопрос на 100%, скажите мне и закройте этот вопрос. Нет проблем.

3

Решение

Стандарт C ++ (в данном случае C ++ 11) не казаться оставить много места для этого. Это прямо указано в 6.5.3 The for statement /1 что (мой акцент):

условие определяет тест, сделано перед каждой итерацией, такой, что цикл завершается, когда условие становится ложным;

Однако, как указано в 1.9 Program execution /1:

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

Это положение иногда называют правилом «как будто», потому что реализация может игнорировать любой Требование настоящего международного стандарта при условии, что результат будет соответствовать требованию, насколько это можно определить из наблюдаемого поведения программы.

Таким образом, если реализация может убедиться, что возвращаемое значение из GetNum() не будет меняться во время цикла, он может совершенно свободно оптимизировать все, кроме первого вызова из существования.

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

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

Единственная проблема, которую я вижу в первом примере кода, состоит в том, что num может существовать дольше, чем необходимо (если его причиной существования является только управление этим циклом). Однако это можно легко исправить, явно ограничив область действия, например, с помощью «small-change»:

{
DWORD num = someOldListImplementation.GetNum();
for (DWORD i = 0; i < num; i++)
{
someOldListImplementation.Get(i);
}
}
// That num is no longer in existence.

или путем включения его в for Само заявление:

for (DWORD num = someOldListImplementation.GetNum(), i = 0; i < num; ++i)
{
someOldListImplementation.Get(i);
}
// That num is no longer in existence.
1

Другие решения

Точный ответ на мой вопрос заключается в использовании

for (auto i = 0, num = x.GetNum(); i < num; ++i)
{

}

так как

  • это предотвращает призывы к GetNum() на каждом цикле
  • переменная num не выставляется за пределы петли

Кредиты переходят на пользователя Nawaz!

Я также использовал ++ i вместо i ++. Причина: https://www.quora.com/Why-doesnt-it-matter-if-we-use-I++-or-++I-for-a-for-loop

0

По вопросам рекламы [email protected]