Вы извлекаете вызов для определения длины массива / строки из заголовка for? - PullRequest
2 голосов
/ 06 июля 2011

Я недавно заметил, что мой коллега делает

int len = foo.length();
for (int i = 0; i < len; ++i)
    doStuff(foo[i]);

Я знаю, что это считалось хорошей практикой в ​​C, где strlen () выполнялся в O (length_of_string). Но я бы ожидал, что более новые языки (скажем, Java или Python) будут хранить длину строки вместе с символами, что позволит length () работать в O (1). Я обычно пишу:

for (int i = 0; i < foo.length(); ++i)
    doStuff(foo[i]);

Сохранение строки кода. Но мой сотрудник заставил меня задуматься ... действительно ли это хорошая практика или не стоит ожидать поведения O (1)?

(В связи с этим: не могут ли современные компиляторы извлекать вызов strlen () изнутри for-header автоматически в эти дни?)

Ответы [ 3 ]

1 голос
/ 06 июля 2011

Эти операторы на самом деле являются двумя разными операторами.

int len = foo.length(); // Will run once
for (int i = 0; i<len;++i)

Здесь i<len будет проверяться каждый цикл, хотя len - это просто переменная, которую можно прочитать.

for (int i = 0; i < foo.length(); ++i)

Здесь i < foo.length() содержит вызов функции, и поскольку длина foo может изменяться в самом цикле (например, вы можете удалить символы foo вместо увеличения i), функция foo.length() будет вызываться каждый разитерация.

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

Дополнительно некоторыеязыки могут допускать что-то вроде этого:

for (int i=0, len=foo.length();i<len;++i)

, что все равно спасает вас.

0 голосов
/ 10 июля 2011

Это не очень зависит от языка. Это зависит от того, насколько умным является компилятор. Если вы можете явно указать, что длина постоянна, весь цикл может быть встроенным, поэтому никаких тестов вообще не будет. Когда дело доходит до Java, я бы поспорил, что компилятор может быть довольно умным, так что вам не нужно быть слишком явным. Вы правы насчет java.lang.String, предварительно рассчитав его длину. Когда дело доходит до сложности, целесообразно определить, какие важные операции вы считаете. Строго говоря, на машине Тьюринга вы должны быть O (n), чтобы найти конец ("$") ввода.

0 голосов
/ 06 июля 2011

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

Кроме того,использование вашего кода может привести к ошибкам при рефакторинге кода.Например, этот цикл никогда не закончится:

for (int i = 0; i < foo.length(); ++i)
{
    doStuff(foo[i]);

    // few line of code, written another man
    doWork(foo); // Passing by reference
}

void doWork(Foo fooObj)
{
    // some work

    fooObj.Add(new SomeObject());
}
...