Если 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 (в котором больше нет точек последовательности) имеет более явную формулировку этого (выделить мое)
При вызове функции (независимо от того, является ли функция встроенной) каждое вычисление значения и побочный эффект, связанные с любым выражением-аргументом, или с постфиксным выражением, обозначающим вызываемую функцию, упорядочены перед выполнением каждого выражения. или оператор в теле вызываемой функции.
person
Johannes Schaub - litb
schedule
02.04.2011
foo()
является параметромbar()
(неявныйthis
-указатель), порядок четко определен. - person Björn Pollex   schedule 02.04.2011obj.foo().bar()
из другие гарантии спец. (подчеркните мое). - person Johannes Schaub - litb   schedule 02.04.2011