Объявление и инициализация переменной в условном операторе или операторе Control в C ++
Автор вопроса: Daniel BinghamОтветов: 9
В книге Страуструпа Язык программирования C ++: Special Edition (3-е изд.) Страуструп пишет, что объявление и инициализация переменных в условных выражениях управляющих операторов не только разрешены, но и приветствуются. Он пишет, что поощряет это, потому что это уменьшает область действия переменных только до той области, для которой они требуются. Так что-то вроде этого ...
if ((int i = read(socket)) < 0) {
// handle error
}
else if (i > 0) {
// handle input
}
else {
return true;
}
... хороший стиль программирования и практика. Переменная i существует только для блока if операторов, для которого она необходима, а затем выходит за пределы области видимости.
Однако эта функция языка программирования, похоже, не поддерживается g ++ (версия 4.3.3, специфичная для Ubuntu компиляция), что меня удивляет. Возможно, я просто вызываю g ++ с флагом, который его выключает (флаги, которые я назвал, -g и -Wall). Моя версия g ++ возвращает следующую ошибку компиляции при компиляции с этими флагами:
socket.cpp:130: error: expected primary-expression before ‘int’
socket.cpp:130: error: expected `)' before ‘int’
При дальнейших исследованиях я обнаружил, что, похоже, я не единственный, у кого компилятор не поддерживает это. И, похоже, возникла некоторая путаница в этом вопросе относительно того, какой именно синтаксис предположительно был стандартным для языка и какие компиляторы с ним компилируются.
Итак, вопрос в том, какие компиляторы поддерживают эту функцию и какие флаги необходимо установить для ее компиляции? Проблема в том, чтобы соответствовать одним стандартам, а не другим?
Кроме того, просто из любопытства, согласны ли люди со Страуструпом в том, что это хороший стиль? Или это ситуация, когда создатель языка получает в голове идею, которая не обязательно поддерживается языковым сообществом?
Я не знаю, какой компилятор поддерживает это, но я лично использую этот подход каждый раз, когда делаю что-то, что не требует этой переменной, кроме использования ее в качестве временной. Тот же вопрос, является ли это плохой практикой? Chezz 04.10.2009
Другой пример: stackoverflow.com/questions/1380135/ Johannes Schaub - litb 05.10.2009
Я бы сказал, что сама идея определения переменных по блокам - плохая практика, потому что она оправдывает длинные методы. Я рекомендую радикальные утверждения Боба Мартина относительно длины функции в его чрезвычайно полезной книге Чистый код; в частности, в любом случае метод действительно не должен иметь более одной управляющей структуры. Keith Pinson 11.01.2013
Разрешено объявить переменную в управляющей части вложенного блока, но в случае if и while переменная должна быть инициализирована числовым или логическим значением, которое будет интерпретироваться как условие. Его нельзя включить в более сложное выражение!
В конкретном случае, который вы показываете, к сожалению, вы не можете найти способ подчиниться.
Я лично считаю хорошей практикой сохранять локальные переменные как можно ближе к их фактическому времени жизни в коде, даже если это звучит шокирующе, когда вы переключаетесь с C на C ++ или с Pascal на C ++ - мы привыкли видеть все переменные в одно место. С некоторой привычкой вы найдете его более читабельным, и вам не придется искать объявление в другом месте. Более того, вы знаете, что до этого момента он не использовался.
Редактировать:
При этом я не считаю хорошей практикой смешивать слишком много в одном заявлении, и я думаю, что это общее мнение. Если вы измените значение переменной, а затем используете его в другом выражении, код будет более читабельным и менее запутанным, если разделить обе части.
Проблема, похоже, заключается в круглых скобках вокруг объявления int. Он должен работать, если вы можете выразить задание и протестировать без них, т.е.
if (int i = read(socket)) {
должно работать, но это означает, что тест != 0, а это не то, что вам нужно.
Ответ 6 · рейтинг 3 · Clifford
Хотя вы можете использовать объявление как логическое выражение, вы не можете разместить объявление в середине выражения. Я не могу избавиться от мысли, что вы неправильно читаете то, что говорит Бьярн.
Этот метод полезен и желателен в основном для управляющих переменных циклов for, но в данном случае я считаю, что он не рекомендуется и не дает ясности. И конечно не работает! ;)
if( <type> <identifier> = <initialiser> ) // valid, but not that useful IMO
if( (<type> <identifier> = <initialiser>) <operator> <operand> ) // not valid
for( <type> <identifier> = <initialiser>;
<expression>;
<expression> ) // valid and desirable
В вашем примере вы вызвали функцию с побочными эффектами в условном выражении, что IMO является плохой идеей, независимо от того, что вы могли бы подумать об объявлении переменной там.
Ответ 7 · рейтинг 3 · White_Pawn
Дополнение к тому, что сказали RedGlyph и Ферруччо. Возможно, мы можем сделать следующее, чтобы по-прежнему объявлять в условном операторе, чтобы ограничить его использование:
Хотя это напрямую не связано с вопросом, во всех примерах на первое место ставится обработка ошибок. Поскольку существует 3 случая (> 0 -> данные, == 0 -> соединение закрыто и ‹0 -> ошибка), это означает, что наиболее распространенный случай получения новых данных требует двух тестов. Проверка на> 0 сначала сократит ожидаемое количество тестов почти вдвое. К сожалению, подход "if (int x = read (socket))", предложенный White_Pawn, по-прежнему требует двух тестов для случая данных, но предложение C ++ 17 может быть использовано для проверки сначала на> 0.