Неопределённое поведение в недостижимом коде
Содержит ли следующий код UB или надо вызвать функцию для этого?
int foo() {
int a = 2 + 3;
// no return
}
int main() {
// foo();
}
Ответы (3 шт):
Нашёл ответ на похожий вопрос. Спасибо LShadow77 за помощь.
https://stackoverflow.com/a/23154502
So, an unreachable statement with UB doesn't give the program UB.
Нет здесь никакого неопределенного поведения.
У UB бывает два вида причин:
Времени компиляции. (Например, использование зарезервированного идетификатора.)
Времени выполнения. (Например целочисленное деление на ноль.)
Во втором случае, чтобы поведение стало неопределенным, выполнение должно достичь1 какого-то участка кода, про который в стандарте написано, что он вызывает неопределенное поведение (или его поведение не описано вообще). (см 1 2 3)
У нас второй случай:
Flowing off the end of a ... function with a cv
voidreturn type is equivalent to areturnwith no operand. Otherwise flowing off the end of a function ... results in undefined behavior.
(выделение добавлено мной)
Написано, "если выполнение выходит из функции...", т.е. во время выполнения. Если бы речь шла о времени компиляции, то так и написали бы: "если любой возможный путь выполнения функции всегда достигает ее конца...".
1 Точнее, UB появляется когда выполнение вызывающего его кода становится неизбежным. Пример: программа может проигнорировать условие if-а и отказаться заходить в ветку, которая всегда вызывает UB.
Я склоняюсь к тому, что неопределенное поведение тут есть. Дело в том, что стандарт позволяет реализации содержать ряд допущений относительно потока исполнения:
6.9.2.2 Forward progress [intro.progress]
1 The implementation may assume that any thread will eventually do one of the following:
— (1.1) terminate,
— (1.2) make a call to a library I/O function,
— (1.3) perform an access through a volatile glvalue, or
— (1.4) perform a synchronization operation or an atomic operation.
То бишь, что поток исполнения в какой-то момент либо завершится, либо вызовет функцию ввода / вывода, либо произведет доступ к некоторому volatile значению или либо сделает синхронизацию или атомарную операцию. А поток исполнении в функции foo из примера просто обрывается, не приводя ни к чему из вышеперечисленного, подрывая допущения, которые может делать конформная реализации.