Код, который я имею, похож на это (все использование показанных сделанных):
bool done = false;
for(int i = 0; i < big; i++)
{
...
for(int j = 0; j < wow; j++)
{
...
if(foo(i,j))
{
done = true;
break;
}
...
}
if(done) break;
...
}
будут любые компиляторы преобразовывать его в это:
for(int i = 0; i < big; i++)
{
...
for(int j = 0; j < wow; j++)
{
...
if(foo(i,j))
goto __done; // same as a labeled break if we had it
...
}
...
}
__done:;
Примечание: В то время как я главным образом интересуюсь если if(done)break;
обойден и удалил как мертвый код, я также интересуюсь если он и done
удален в целом.
Очевидно, это зависит от компилятора. Лучшее, что можно сделать, если вы не уверены, - это просмотреть вывод сборки компилятора (во всех популярных компиляторах есть переключатель для этого). Даже если вы не знакомы со сборкой, вы можете хотя бы сравнить отладочную версию с оптимизированной версией.
При этом это одна из немногих ситуаций, когда goto
НЕ является плохой идеей . Смело используйте его, чтобы вырваться из внутренних петель.
Править
Просто попробовал следующее в VS2010, и он действительно оптимизирует внешнее условие:
bool done = false;
for(int i = 0; i < 10; i++)
{
for(int j = 0; j < 10; j++)
{
if(i == 7 && j == 3)
{
done = true;
break;
}
}
if(done) break;
}
return 0;
Я не пытаюсь шутить, но ... какое это имеет значение? В общем, я считаю, что лучше всего позволить компиляторам выполнять свою работу, и эта задача - создавать «лучший» (обратите внимание, что «лучший» может варьироваться в зависимости от ваших потребностей) скомпилированный код с учетом вашего исходного кода. Любые соображения производительности в вашем коде следует определять с помощью профилировщика и хорошего рабочего знания алгоритмической сложности.
Если вам просто любопытно, не обращайте внимания на этот комментарий. Но если вы намерены как-то оптимизировать свой код, я думаю, есть гораздо лучшие пути.
Я пробовал GCC 4.2.1 со следующим:
// Prevent optimizing out calls to foo and loop unrolling:
extern int big, wow;
bool foo(int,int);
void
bar()
{
int done = false;
for(int i = 0; i < big; i++)
{
for(int j = 0; j < wow; j++)
{
if(foo(i,j))
{
done = true;
break;
}
}
if(done)
break;
}
}
... и он сразу попадает в почтовый ящик с -O3
:
33: e8 fc ff ff ff call 34 <bar()+0x34> ; call to foo*
38: 84 c0 test %al,%al
3a: 74 e5 je 21 <bar()+0x21> ; next loop iteration
3c: 83 c4 10 add $0x10,%esp
3f: 5b pop %ebx
40: 5e pop %esi
41: 5d pop %ebp
42: c3 ret
** * Это из несвязанного объектного файла, вызов 34
на самом деле является вызовом foo
.
Компилятор GNU делает именно это, начиная с уровня оптимизации -O1 (я использую gcc 4.5.1 на x86_64)
call _Z3fooii // al = foo(i,j)
testb %al, %al
jne .L14
...
, где .L14 - это метка, размещенная точно там, где вы поместили __done:
Возможно, лучше спросить: какой современный компилятор не выполняет эту оптимизацию?