Ответ 1
strlen вычисляется на каждой итерации цикла.
Что потрачено впустую в примере из Руководства Cpp Core?
Стр .9: Не тратьте время и пространство
[...]
void lower(zstring s) { for (int i = 0; i < strlen(s); ++i) s[i] = tolower(s[i]); }
Да, это пример из производственного кода. Мы оставляем читателю понять, что было потрачено впустую.
из https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rp-waste
strlen вычисляется на каждой итерации цикла.
strlen
вызывается каждый раз, когда проверяется условие цикла, и принимает O (n) время на вызов, поэтому общее время цикла равно O (n ^ 2).
Много времени тратится впустую, и ошибка сегментации может возникать как автор кода, увеличивающий s
, а не i
в цикле:
for (int i = 0; i < strlen(s); ++s)
//right here ^^^^
Как уже указывали другие участники, strlen(s)
вызывается несколько раз, потому что он находится в условии, подразумевая, что он должен быть кэширован и повторно использован.
Но strlen(s)
вообще не нужно называть! s
является (или неявно конвертируется) в nul-terminated char
массив, так как это ожидает strlen
. Поэтому мы можем просто использовать это свойство для нашего собственного цикла.
void lower(zstring s) {
for (char *p = s; *p; ++p)
*p = std::tolower((unsigned char)*p);
}
Если в классе zstring
не существует какой-либо очень неинтуитивной семантики, функция в ее текущей форме является пустой тратой пространства времени и, поскольку ее "результат" не может использоваться после функции - оно передается как значение и не возвращается.
Поэтому, чтобы не тратить время на бесполезное вычисление строчных букв, которые нельзя использовать, а также на пространство при копировании переданного параметра, я бы передал ссылку!