Применяет ли C ++ операторы return? - PullRequest
7 голосов
/ 06 июля 2010

Хорошо, маленькая странность, которую я обнаружил с помощью моего компилятора C ++.

У меня был не слишком сложный фрагмент кода для рефакторинга, и мне случайно удалось уйти по пути, в котором не было оператора return. Виноват. С другой стороны, он был скомпилирован и вышел из строя, когда я запустил его, и этот путь был найден, очевидно.

Вот мой вопрос: это ошибка компилятора, или нет гарантии, что компилятор C ++ обеспечит выполнение оператора return в не возвращаемой функции возврата?

О, и чтобы быть ясным, в этом случае это было ненужным, если заявление без сопровождающего другого. Нет gotos, нет выходов, нет прерываний.

Ответы [ 3 ]

13 голосов
/ 06 июля 2010

Нет никакой гарантии, что компилятор C ++ обеспечит это. Функция C ++ может выпрыгнуть из потока управления с помощью механизмов, неизвестных компилятору. Переключение контекста, когда C ++ используется для написания ядра ОС, является примером этого. Необработанное исключение, выданное вызываемой функцией (код которой не обязательно доступен вызывающей стороне), является еще одним.

Некоторые другие языки, такие как Java, явно предписывают, что при наличии знаний, доступных во время компиляции, все пути возвращают значение. В C ++ это не так, как и во многих других случаях в языке, например, доступ к массиву за его пределами также не проверяется.

11 голосов
/ 06 июля 2010

Лично я считаю, что это должно быть ошибкой:

int f() {
}

int main() {
    int n = f();
    return 0;
}

но большинство компиляторов воспринимают это как предупреждение, и вам, возможно, даже придется использовать переключатели компилятора, чтобы получить это предупреждение. Например, на g ++ вам нужно -Wall, чтобы получить:

[neilb@GONERIL NeilB]$ g++ -Wall nr.cpp
nr.cpp: In function 'int f()':
nr.cpp:2: warning: no return statement in function returning non-void

Конечно, с g ++ вы всегда должны компилировать по крайней мере с -Wall в любом случае.

4 голосов
/ 06 июля 2010

Компилятор не применяет это, потому что вы знаете, какие пути практически возможны, а компилятор - нет.Компилятор обычно знает только об этом конкретном файле, а не о других, которые могут повлиять на поток внутри любой данной функции.Так что это не ошибка.

В Visual Studio это предупреждение.И мы должны обратить внимание на все предупреждения .... верно?:)

Редактировать : Кажется, есть некоторые дискуссии о том, когда это может произойти.Вот модифицированный, но реальный пример из моей личной библиотеки кодов:

enum TriBool { Yes, No, Maybe };

TriBool GetResult(int input) {
    if (TestOne(input)) {
        return Yes;
    } else if (TestTwo(input)) {
        return No;
    }
}

Имейте в виду, потому что это старый код.Первоначально там было «возможно, еще возврат».:) Если TestOne и TestTwo находятся в другом модуле компиляции, то когда компилятор нажимает этот код, он не может сказать, могут ли TestOne и TestTwo оба возвращать false для данного входа.Вы, как программист, написавший TestOne и TestTwo, знаете, что если TestOne завершится неудачей, TestTwo будет успешным.Возможно, у этих тестов есть побочные эффекты, поэтому они должны быть выполнены.Было бы лучше написать это без "если еще"?Может быть.Наверное.Но дело в том, что это допустимый C ++, и компилятор не может знать, можно ли выйти без оператора return.Я согласен, это некрасивое и нехорошее кодирование, но это законно, и Visual Studio выдаст вам предупреждение, но скомпилирует.

Помните, что C ++ не предназначен для защиты вас от себя.Речь идет о том, чтобы позволить вам делать то, что ваше сердце желает в рамках языковых ограничений, даже если это включает в себя выстрел в себя.

...