Порядок оценки аргументов функции и аргументов по умолчанию
Недавно я столкнулся со следующей ситуацией:
#include <iostream>
int *p = 0;
int f() {
p = new int(10);
return 0;
}
void g(int x, int *y = p) {
std::cout << y << std::endl;
}
int main() {
g(f());
}
Это довольно тонко, поскольку вы обычно не ожидаете, что аргументы по умолчанию будут меняться во время их оценки для вызова функции. Я должен был взглянуть на сборку, чтобы обнаружить эту ошибку.
Теперь мой вопрос: Это действительно поведение undefined, так как нет никаких гарантий относительно порядка оценки аргументов функции?
Ответы
Ответ 1
Порядок оценки (т.е. определение значения) аргументов функции не указан. Компилятор может свободно выполнять их в любом порядке и даже перемешать, если нет других факторов, препятствующих этому.
Оценка аргументов по умолчанию происходит в контексте вызывающего, а не вызываемого абонента. Таким образом, вызов для f() необходим для одного аргумента и чтения глобальной переменной p для другой. Какой порядок это происходит, не указан, поэтому глобальный может быть прочитан до или после вызова функции f().
Ответ 2
Если я правильно понял, ваш вызов
g(f());
эквивалентно
g(f(), p);
из-за объявления
void g(int x, int *y = p);
И аргументы функции g
, f()
и p
, могут быть оценены в любом порядке, поэтому вы можете получить g
с y
, назначенным либо нулем (если сначала оценивается p
, то оно возвращает свое начальное значение) или вновь выделенный указатель массива (если f()
оценивается первым и присваивает новое значение p
как его побочный эффект).