31. Не пишите код, который зависит от порядка вычислений аргументов функции
31. Не пишите код, который зависит от порядка вычислений аргументов функции
Резюме
Порядок вычисления аргументов функции не определен, поэтому никогда не полагайтесь на то, что аргументы будут вычисляться в той или иной очередности.
Обсуждение
На начальных этапах развития языка C регистры процессора были драгоценным ресурсом и компиляторы решали трудные задачи эффективного их использования в сложных выражениях высокоуровневых языков. Для того чтобы позволить компилятору генерировать более быстрый код, создатели C дали распределителю регистров дополнительную степень свободы. При вызове функции порядок вычисления ее аргументов оставался неопределенным. Эта аргументация, вероятно, существенно менее важна в настоящее время, но главное, что порядок вычисления аргументов функций в C++ не определен и варьируется от компилятора к компилятору (см. также рекомендацию 30).
В связи с этим необдуманные действия программиста могут привести к большим неприятностям. Рассмотрим следующий код:
void Transmogrify(int, int);
int count = 5;
Transmogrify(++count, ++count); // Порядок вычислений
// неизвестен
Все, что мы можем сказать определенного, — это то, что при входе в тело функции Transmogrify значение переменной count будет равно 7 — но мы не можем сказать, какой аргумент будет равен 6, а какой — 7. Эта неопределенность остается и в гораздо менее очевидных случаях, таких как функции, модифицирующие свои аргументы (или некоторое глобальное состояние) в качестве побочного действия:
int Bump(int& x) { return ++x; }
Transmogrify(Bump(count), Bump(count)); // Результат
// неизвестен
Согласно рекомендации 10, следует в первую очередь избегать глобальных и совместно используемых переменных. Но даже если вы благополучно устраните их, некоторый другой код может этого не сделать. Например, некоторые стандартные функции имеют побочные действия (например, strtok, а также разные перегруженные операторы operator<<, принимающие в качестве аргумента ostream).
Рецепт очень прост — использовать именованные объекты для того, чтобы обеспечить порядок вычислений (см. рекомендацию 13):
int bumped = ++count;
Transmogrify(bumped, ++count); // все в порядке
Ссылки
[Alexandrescu00c] • [Cline99] §31.03-05 • [Dewhurst03] §14-15 • [Meyers96] §9-10 • [Stroustrup00] §6.2.2, §14.4.1 • [Sutter00] §16 • [Sutter02] §20-21
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
Назначение имен тегов и атрибутов зависит от регистра
Назначение имен тегов и атрибутов зависит от регистра В документах HTML имена тегов и атрибутов не зависят от регистра символов, так что, например, запись <TABLE>, <TaBle> или <table> означает один и тот же тег таблицы. Однако в XHTML это разные теги. То же самое касается имен
Выполнение обещания зависит от другого человека X
Выполнение обещания зависит от другого человека X Обещайте только то, что находится под вашим полным контролем. Например, если вашей целью является завершение модуля, в работе над которым также участвует другая группа, вы не можете обещать завершить модуль с полной
(3.28) Как поменять цвет, на который меняются буквы при наведении на них мышки в windows explorer, при включенной функции одного клика?
(3.28) Как поменять цвет, на который меняются буквы при наведении на них мышки в windows explorer, при включенной функции одного клика? В реестре по адресу HKEY_CURRENT_USERControl PanelAppearanceSchemes в любой схеме изменяется значение по адресу 02BD (02B8 – in the 5th column) это и будет HotTrackingColor. Но при
Пишите, Шура, пишите
Пишите, Шура, пишите Метки: темы блога, автор блога, маркетинг, пользовательский контентХороший маркетинг начинается с хорошего продукта. Блог компании – это тоже своего рода продукт, постоянно изменяемый автором. Складывается он из оформления, юзабилити и содержания.
Все зависит от того, с какой стороны подойти
Все зависит от того, с какой стороны подойти Если вы попросите веб-аналитика дать определение сценарию, он наверняка вспомнит о «воронке продаж» и скажет, что сценарий – это последовательность шагов, которые делает клиент в процессе покупки. На каждом этапе покупатель
Как мы чувствуем. От чего зависит наше настроение
Как мы чувствуем. От чего зависит наше настроение Еще Эклизиаст сказал, что глупый живет в доме радости, а умный в доме печали. Иными словами, "от многие знания — многие печали". Так к чему мы стремимся? Что важнее, быть умным или быть счастливым? Есть третий вариант — быть
Выполнение вычислений в запросах
Выполнение вычислений в запросах В строках запроса допускается выполнение вычислений. Для этого нужно просто заменить имя поля в предложении SELECT именем арифметического выражения. Допустим, вам нужно создать запрос для вычисления налога с продаж для складских запасов
12. Кодирование параллельных вычислений
12. Кодирование параллельных вычислений РезюмеЕсли ваше приложение использует несколько потоков или процессов, следует минимизировать количество совместно используемых объектов, где это только можно (см. рекомендацию 10), и аккуратно работать с
88. В качестве аргументов алгоритмов и компараторов лучше использовать функциональные объекты, а не функции
88. В качестве аргументов алгоритмов и компараторов лучше использовать функциональные объекты, а не функции РезюмеПредпочтительно передавать алгоритмам функциональные объекты, а не функции, а компараторы ассоциативных контейнеров просто должны быть функциональными
5.3. Выполнение вычислений с датами и временем
5.3. Выполнение вычислений с датами и временем ПроблемаТребуется узнать количество времени, прошедшего между двумя точками даты/времени.РешениеЕсли обе временные точки находятся между 1970 и 2038 годами, то используйте тип time_t и функцию difftime, определенную в заголовочном
Структуры в качестве аргументов функции
Структуры в качестве аргументов функции В не расширенном языке Си можно передавать функции адрес структуры. Например, если montana является структурной переменной структурного типа player, мы можем обратиться к функции следующим образом: stats(&montana);Функция stats( ) будет иметь
Вызов функции с переменным числом аргументов
Вызов функции с переменным числом аргументов Для вызова функции с переменным числом аргументов не требуется никаких специальных действий: в вызове функции просто задается то число аргументов, которое нужно. В предварительном объявлении (если оно есть) переменное число
Функции работы со списком аргументов
Функции работы со списком аргументов Функция Краткое описание va_arg выбрать аргумент из списка va_end переустановить указатель va_start установить указатель на начало списка аргументов Эти макроопределения дают возможность получить доступ к аргументам функции, когда
Объектно-ориентированный стиль вычислений
Объектно-ориентированный стиль вычислений Обратимся теперь к фундаментальным свойствам класса POINT и попытаемся понять, как устроено типичное тело подпрограммы и составляющие его инструкции. Далее выясним, каким образом класс и его компоненты могут использоваться
Повторение вычислений
Повторение вычислений Инструкция повторного выполнения рассматривалась при обсуждении исключительных ситуаций (лекция 12). Она появляется только в предложении rescue, повторно запуская тело подпрограммы, работа которой была