Я часто вижу в коде C и C ++ следующее соглашение:
some_type val;
val = something;
some_type *ptr = NULL;
ptr = &something_else;
вместо
some_type val = something;
some_type *ptr = &something_else;
Сначала я предполагал, что это привычка, оставшаяся со времен, когда вам приходилось объявлять все локальные переменные в верхней части области видимости. Но я научился не бросать так быстро привычки разработчиков-ветеранов. Итак, есть ли веская причина для объявления в одной строке и последующего назначения?
Ответы:
С
В C89 все объявления должны были находиться в начале области видимости (
{ ... }
), но это требование было быстро отброшено (сначала с расширениями компилятора, а затем со стандартом).C ++
Эти примеры не совпадают.
some_type val = something;
вызывает конструктор копирования, в то время какval = something;
вызывает конструктор по умолчанию, а затемoperator=
функцию. Это различие часто критично.Привычки
Некоторые люди предпочитают сначала объявлять переменные, а затем определять их, в случае, если они переформатируют свой код позже с объявлениями в одном месте и определением в другом.
Что касается указателей, некоторые люди просто имеют привычку инициализировать каждый указатель
NULL
илиnullptr
независимо от того, что они делают с этим указателем.источник
some_type
конструктор, принимающий вsomething
качестве единственного аргумента. Это очень интересный и необычный крайний случай в C ++ ... это означает, что существует презумпция семантического значения этих операций.Вы пометили свой вопрос C и C ++ одновременно, в то время как ответ значительно отличается в этих языках.
Во-первых, формулировка названия вашего вопроса неверна (или, точнее, не имеет отношения к самому вопросу). В обоих ваших примерах переменная объявляется и определяется одновременно в одну строку. Разница между вашими примерами в том, что в первом случае переменные либо остаются неинициализированными, либо инициализируются фиктивным значением, а затем ему присваивается значимое значение. Во втором примере переменные инициализируются сразу.
Во-вторых, в языке C ++, как заметил @nightcracker в своем ответе, эти две конструкции семантически различны. Первый опирается на инициализацию, а второй - на присвоение. В C ++ эти операции перегружаются и поэтому могут потенциально привести к различным результатам (хотя можно заметить, что создание неэквивалентных перегрузок инициализации и присваивания не является хорошей идеей).
В оригинальном стандартном языке C (C89 / 90) запрещено объявлять переменные в середине блока, поэтому вы можете увидеть переменные, объявленные неинициализированными (или инициализированные фиктивными значениями) в начале блока, а затем присвоенные значимым значения позже, когда эти значимые значения становятся доступными.
В языке C99 можно объявить переменные в середине блока (как в C ++), что означает, что первый подход необходим только в некоторых конкретных ситуациях, когда инициализатор неизвестен в точке объявления. (Это относится и к C ++).
источник
some_type val;
сразу объявляет и определяет переменнуюval
. Это то, что я имел в виду в своем ответе.Я думаю, что это старая привычка, оставшаяся от времен "местной декларации". И поэтому как ответ на ваш вопрос: нет, я не думаю, что есть веская причина. Я никогда не делаю это сам.
источник
Я сказал кое-что об этом в своем ответе на вопрос Helium3 .
По сути, я говорю, что это наглядное пособие, чтобы легко увидеть, что изменилось.
а также
источник
Другие ответы довольно хороши. В Си есть некоторая история об этом. В C ++ есть разница между конструктором и оператором присваивания.
Я удивлен, что никто не упоминает дополнительный пункт: хранение объявлений отдельно от использования переменной иногда может быть намного более читабельным.
Визуально говоря, при чтении кода более приземленные артефакты, такие как типы и имена переменных, не являются тем, что бросается в глаза. Это заявления, которые вы обычно больше всего интересуете, тратите большую часть времени, уставившись на них, и поэтому есть тенденция взглянуть на все остальное.
Если у меня есть несколько типов, имен и назначений, которые происходят в одном и том же ограниченном пространстве, это немного перегружает информацию. Кроме того, это означает, что в пространстве происходит нечто важное, на что я обычно смотрю.
Это может показаться немного нелогичным, но это один из примеров, когда ваш источник занимает больше вертикального пространства, что может сделать его лучше. Я вижу это как сродни тому, почему вы не должны писать переполненные строки, которые делают сумасшедшие арифметические действия и присваивания указателей в узком вертикальном пространстве - только потому, что язык позволяет вам сойти с рук с такими вещами, не означает, что вы должны делать это все время. :-)
источник
В C это было стандартной практикой, потому что переменные должны были объявляться в начале функции, в отличие от C ++, где она могла быть объявлена в любом месте тела функции для последующего использования. Указатели были установлены в 0 или NULL, потому что он просто проверял, что указатель не указывает на мусор. В противном случае, я не могу придумать существенного преимущества, которое заставляет любого делать это.
источник
Плюсы для локализации определений переменных и их значимой инициализации:
если переменным обычно присваивается значимое значение, когда они впервые появляются в коде (другая точка зрения на ту же вещь: вы задерживаете их появление до тех пор, пока значимое значение не становится доступным), тогда нет никакой возможности их случайного использования с бессмысленным или неинициализированным значением ( что может легко произойти, если некоторая инициализация случайно пропущена из-за условных операторов, оценки короткого замыкания, исключений и т. д.)
может быть более эффективным
operator=
иногда может быть менее эффективным и требовать временного объектаминимизация области видимости переменных в свою очередь минимизирует среднее количество переменных одновременно в области видимости :
иногда более кратким, поскольку вы не повторяете имя переменной в определении, а не в первоначальном значимом присваивании
необходимо для определенных типов, таких как ссылки и когда вы хотите, чтобы объект
const
Аргументы для группировки определений переменных:
иногда удобно и / или лаконично выделить тип ряда переменных:
the_same_type v1, v2, v3;
(если причина в том, что имя типа слишком длинное или сложное,
typedef
иногда может быть лучше)иногда желательно сгруппировать переменные независимо от их использования, чтобы подчеркнуть набор переменных (и типов), участвующих в какой-либо операции:
type v1;
type v2;
type v3;
Это подчеркивает общность типов и делает их немного более легкими для изменения, но при этом придерживается переменной для каждой строки, что облегчает копирование-вставку,
//
комментирование и т. Д.Как это часто бывает в программировании, хотя в большинстве случаев одно практическое преимущество может быть явным эмпирическим преимуществом, в некоторых случаях другое может быть гораздо лучше.
источник