Не возвращая значения, из функции с не пустым типом возврата
Я читал здесь о том, как:
В C++:
- Не возвращаться из не пустых функций - неопределенное поведение.
... analysis requires inspection of the entire program, which is incompatible with separate compilation, and which is not even possible in the general case ...
Из того, что я сделал из нескольких ответов на этой странице, трудно, а иногда даже невозможно проверить наличие оператора возврата в функциях. То, что не возвращаются из не пустых функций, было оставлено неопределенным поведением по стандарту C++.
Однако я слышал, что в Java то же самое сообщается как ошибка во время компиляции.
Q. Правильно ли мое понимание? И как Java достигает того же?
Изменить: Просто чтобы быть ясно, я заинтересован в понимании:
Если он оставлен неопределенным в стандарте C++ для трудностей реализации, связанных с компилятором, как Java может достичь того же.
И если это не так сложно сделать, разве стандарт C++ не определил бы это как ошибку?
5 ответов
Java делает это, отказываясь запускать некоторые программы, даже если они всегда возвращают значение. Возьми следующий (глупый) метод
public boolean test() {
boolean var=true;
if(var)
return true;
}
Метод всегда возвращает true, но java все равно откажется принять его как действительный. Тот же метод в C++ будет допустимым, потому что он всегда возвращает значение.
Итак, подведем итог: Java откажется от вашего метода, если компилятор не сможет доказать, что он всегда будет возвращать значение. Иногда это будет отклонять методы, которые всегда возвращают значение.
C++ Просто верьте программисту, что он всегда возвращает значение, а затем взрывается во время выполнения, если программист не смог что-то вернуть.
Java может потребовать от вас написания кода, который никогда не будет доступен. Рассмотрим что-то вроде:
void neverReturns() { throw SomeException(); }
MyType function() { neverReturns(); }
Понятно, что ты никогда не упадешь с конца function()
, но Java все равно требует оператора возврата.
Однако в языках есть существенное различие, которое мотивирует тот факт, что C++ не требует оператора return.
Java имеет очень ограниченный набор объектов значений (например, int
или жеdouble
), все из которых имеют легко построенные значения (например, 0
или же 0.0
); все остальное является указателем (который будет приниматьnull
). Таким образом, у вас всегда есть что-то простое, чтобы вернуться в случае, если вы знаете, что это не имеет значения. В C++ определяемые пользователем типы могут (и обычно имеют) семантику значений и очень часто не имеют конструкторов по умолчанию или чего-либо еще, что вы можете легко создать. Представьте себе, что необходимо предоставить отчет о возврате заfunction()
если единственный не копирующий конструктор MyType
требовалось два или три аргумента, все они типа, которые также не имели конструкторов значений. Где бы все Java потребовалось бы return null;
,
Все известные мне компиляторы C++ сообщат об ошибке или предупреждении, если существует путь к коду, который не return
из непустой функции.
Как отмечают комментаторы, обратное не всегда верно. Компилятор может выдать предупреждение по ошибке, потому что он не может правильно "понять" код.
Да, ваше понимание верно. Способ, которым java делает это, заключается в строгости и выдаче ошибок даже для методов, которые всегда возвращают значение.
Предположим, у вас есть следующий метод. Мы знаем, что он всегда будет возвращать значение, потому что охватываются все случаи: либо больше нуля, либо меньше или равно нулю. Однако java не знает этого, он видит "если" с возвратом, "еще, если" с возвратом, но без "другого" и, следовательно, без возврата, и, следовательно, сообщит об ошибке.
int foo( int a ) {
if ( a > 0 ) {
return -1;
}
else if ( a <= 0 ) {
return 1;
}
}
чтобы исправить код для Java нужно удалить, если из остального
int foo( int a ) {
if ( a > 0 ) {
return -1;
}
else /*if ( a <= 0 )*/ {
return 1;
}
}
Компилятору Java нужно просто следовать указаниям языка Java:
(8.4.7) Если объявлен метод с возвращаемым типом, то возникает ошибка времени компиляции, если тело метода может завершиться нормально (§14.1).
(14.1) Однако некоторые события могут помешать нормальному завершению оператора:
1. Операторы break (§14.15), continue (§14.16) и return (§14.17) вызывают передачу управления, которая может помешать нормальному завершению операторов, которые их содержат.
2. Оценка некоторых выражений может вызвать исключения из виртуальной машины Java (§15.6). Явный оператор throw (§14.18) также приводит к исключению. Исключение вызывает передачу управления, которая может помешать нормальному завершению операторов.
......
Гораздо более подробно о завершении обычно определяется в JLS, особенно в §14.