Если f () и g () оба имеют побочные эффекты для некоторого общего объекта, то поведение не определено, потому что порядок выполнения неизвестен.
Это не правда.Вызовы функций не чередуются, и перед входом в функции и перед выходом из функции существует точка последовательности.Все побочные эффекты в g
, относящиеся к побочным эффектам в f
, разделены как минимум одной последовательностью.Поведение не является неопределенным.
Как следствие, порядок выполнения функций f
и g
не определен, но после выполнения одной функции выполняются только оценки этой функции, а другой функции "приходится ждать».Возможны разные наблюдаемые результаты, но это не означает, что произошло неопределенное поведение.
Теперь мне было интересно, что происходит, когда вы цепляете функции-члены на объекте.
Если у вас есть obj.foo().bar()
, вам нужно сначала оценить obj.foo()
, чтобы узнатьдля какого объекта вы вызываете функцию bar
, что означает, что вам нужно ждать, пока obj.foo()
вернется и выдаст значение.Это, однако, не обязательно означает, что все побочные эффекты, вызванные оценкой obj.foo()
, закончены.После оценки выражения вам потребуется точка последовательности , чтобы эти побочные эффекты считались завершенными.Поскольку существует точка последовательности перед возвратом из obj.foo()
, а также перед вызовом bar()
, у вас фактически есть определенный порядок выполнения побочных эффектов, инициированный путем вычисления выражений в foo
и bar
соответственно.
Для более подробного объяснения причина, по которой foo
вызывается до bar
, в вашем примере аналогична причине, по которой i++
сначала увеличивается до вызова функции f
в следующем.
int i = 0;
void f() {
std::cout << i << std::endl;
}
typedef void (*fptype)();
fptype fs[] = { f };
int main() {
fs[i++]();
}
Вопрос, который следует задать здесь: будет ли эта программа печатать 0
, 1
или ее поведение не определено или не указано?Ответ заключается в том, что выражение fs[i++]
обязательно должно быть сначала оценено перед вызовом функции, а перед вводом f
существует точка последовательности, значение i
внутри f
равно 1
.
Я не думаю, что вам нужно расширять область действия неявного параметра объекта до точек последовательности, чтобы объяснить ваш случай, и вы, конечно, не можете расширить его, чтобы объяснить этот случай (который, я надеюсь, является определенным поведением).
Черновик C ++ 0x (у которого больше нет точек последовательности) имеет более четкую формулировку этого (выделите мое)
При вызове функции (независимо от того, является ли функция встроенной), каждое вычисление значения и побочный эффект, связанный с любым выражением аргумента, или с выражением постфикса, обозначающим вызываемую функцию , секвенируется перед выполнением каждого выражения или оператора в телевызываемая функция.