Зачем разделять определение и инициализацию переменных в C++?

в настоящее время я работаю над довольно старым кодом C++ и часто нахожу такие вещи, как

int i;
i = 42;

или

Object* someObject = NULL;
someObject = new Object();

или даже

Object someObject;
someObject = getTheObject();

Я полностью понимаю, что делает этот код, но я действительно не знаю, когда такое разделение определения переменных и инициализации может быть полезно. Я искал некоторые объяснения, но всегда заканчивался списками инициализации членов или вопросом, когда вы должны определить свой локальный переменная.

В конце концов, я не понимаю, почему кто-то мог намеренно написал этот код. Он просто разбивает определение и инициализацию на две последующие строки и создает накладные расходы – в последнем случае он создает объект, используя конструктор по умолчанию, только чтобы уничтожить его в следующей строке.

мне интересно, должен ли я просто изменить код

int i = 42;
Object* someObject = new Object();
Object someObject = getTheObject();

может ли это привести к каким-либо проблемам?

8 ответов


Object someObject;
someObject = getTheObject();

используется оператор присваивания.

Object someObject = getTheObject();

используется конструктор копирования.

кроме того, предлагаемые изменения эквивалентны, и вы должны их реализовать. Разница между оператором копирования ctor/присваивания ожидается чтобы получить тот же результат, это не применяется языком, хотя.

Я не вижу веской причины разделять объявление и назначение, как это делает исходный код , хотя для всех практические цели он не вводит накладные расходы (за исключением объекта)


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

поскольку вы говорите, что это довольно старый код C++, он может использовать то же соглашение, что и пережиток практики C.

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


изменение вы предлагаете настоятельно рекомендуется! Это часть важной идиомы в программировании на C++, а именно Приобретение Ресурсов Инициализация.


рассмотрим следующий случай:

SomeType object;
if( whateverCondition ) {
   object = getObjectOneWay();
} else {
   object = getObjectAnotherWay();
}

таким образом, ясно, что обе ветви присваивают переменную, а ее начальное значение не имеет значения. Однако это редко стоит того.


int i;
i = 42;

это не отдельное определение переменной и инициализации.

это отдельное объявление переменной и задание. Я не вижу причин для этого. Если вы знаете значение в момент объявления переменной, то инициализируйте его прямо тогда. Поэтому ваш вопрос не имеет никакого объяснения.

конечно, если вы не знаете значение во время объявления, то вы не знаете есть любой выбор, вам нужно задание затем.


зачем разделять определение и инициализацию переменных в C++?

вы не разделили определение и инициализацию. Вы только что присвоили переменную / объект (определенному) значению в фрагменте кода. Таким образом, название вводит в заблуждение.

Object someObject;
someObject = getTheObject();

отличается от Object someObject = getTheObject();

someObject = getTheObject(); вызывает оператор присваивания Object класс а в Object someObject = getTheObject(); конструктор копирования класса вызывается. Это также известен под названием скопировать инициализации

хороший компилятор может генерировать тот же код в случае int i; i = 42; и int i =42. Накладных расходов будет немного.

кстати, я всегда предпочитаю int i = 42 to int i; i=42 и

Object someObject = getTheObject(); to

Object someObject; someObject = getTheObject();

П. С. : int i = 42 определяет и инициализирует i, тогда как int i; i=42 определяет i и затем назначает 42 к нему.


существует хорошая техническая причина на аппаратном обеспечении на базе ROM, это не проблема стиля:

в встроенных системах на основе ROM/EEPROM это влияет на то, где в двоичном файле записывается значение. Неинициализированные переменные записываются .bss, тогда как инициализированные переменные записываются .данные. Преждевременная инициализация раздует ваше пространство ROM, что на старых встроенных системах может привести к большим, большим проблемам. Если вы работаете в системе с небольшим ПЗУ, вы может закончиться память, если вы инициализируете без необходимости. Некоторые тупые компиляторы будут даже обращаться непосредственно в ПЗУ, что делает эти значения эффективно только для чтения, если вы не будете осторожны.

например, см. Этот пример GameBoy для более подробного объяснения: http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_varinit


нет. Это вопрос стиля.

однако, если он когда-либо хотел переместить объявление из функции, было бы меньше редактирования, если объявление и инициализация разделены.