Как уже отмечалось, на этот счет существуют две точки зрения.
1) Объявите все в верхней части функций, потому что год 1987.
2) Объявите как можно ближе к первому использованию и в минимально возможном объеме.
Мой ответ - ДЕЛАЙТЕ ОБОИХ! Позволь мне объяснить:
Для длинных функций 1) очень затрудняет рефакторинг. Если вы работаете в кодовой базе, где разработчики выступают против идеи подпрограмм, тогда у вас будет 50 объявлений переменных в начале функции, и некоторые из них могут быть просто «i» для цикла for, который находится в самом начале внизу функции.
Поэтому из этого я развил посттравматическое стрессовое расстройство и попытался применить вариант 2) неукоснительно.
Я вернулся к первому варианту по одной причине: короткие функции. Если ваши функции достаточно короткие, то у вас будет несколько локальных переменных, и, поскольку функция короткая, если вы поместите их в начало функции, они все равно будут близки к первому использованию.
Кроме того, анти-шаблон «объявить и установить в NULL», когда вы хотите объявить вверху, но вы не выполнили некоторые вычисления, необходимые для инициализации, разрешается, потому что вещи, которые вам нужно инициализировать, скорее всего, будут получены в качестве аргументов.
Итак, теперь я считаю, что вы должны объявлять функции в верхней части и как можно ближе к первому использованию. Так что ОБА! И способ сделать это - использовать хорошо разделенные подпрограммы.
Но если вы работаете над длинной функцией, то лучше всего используйте ее в первую очередь, потому что так будет легче извлекать методы.
Мой рецепт такой. Для всех локальных переменных возьмите переменную и переместите ее объявление в конец, скомпилируйте, а затем переместите объявление непосредственно перед ошибкой компиляции. Это первое использование. Сделайте это для всех локальных переменных.
int foo = 0;
<code that uses foo>
int bar = 1;
<code that uses bar>
<code that uses foo>
Теперь определите блок области видимости, который начинается перед объявлением, и переместите конец, пока программа не скомпилируется.
{
int foo = 0;
<code that uses foo>
}
int bar = 1;
<code that uses bar>
>>> First compilation error here
<code that uses foo>
Это не компилируется, потому что есть еще код, использующий foo. Мы можем заметить, что компилятор смог пройти через код, который использует bar, потому что он не использует foo. На данный момент есть два варианта. Механический - просто переместить "}" вниз до тех пор, пока он не скомпилируется, а другой вариант - проверить код и определить, можно ли изменить порядок на:
{
int foo = 0;
<code that uses foo>
}
<code that uses foo>
int bar = 1;
<code that uses bar>
Если порядок можно изменить, вероятно, это то, что вам нужно, потому что это сокращает срок службы временных значений.
Еще одно замечание: нужно ли сохранять значение foo между блоками кода, которые его используют, или это может быть просто другой foo в обоих. Например
int i;
for(i = 0; i < 8; ++i){
...
}
<some stuff>
for(i = 3; i < 32; ++i){
...
}
Эти ситуации требуют большего, чем моя процедура. Разработчик должен будет проанализировать код, чтобы определить, что делать.
Но первый шаг - найти первое применение. Вы можете сделать это визуально, но иногда проще удалить объявление, попытаться скомпилировать и просто вернуть его выше первого использования. Если это первое использование находится внутри оператора if, поместите его туда и проверьте, компилируется ли он. Затем компилятор определит другие варианты использования. Попробуйте создать блок области видимости, охватывающий оба использования.
После того, как эта механическая часть сделана, становится легче анализировать, где находятся данные. Если переменная используется в большом блоке области видимости, проанализируйте ситуацию и посмотрите, используете ли вы одну и ту же переменную для двух разных вещей (например, «i», который используется для двух циклов for). Если использования не связаны, создайте новые переменные для каждого из этих несвязанных видов использования.