Какая польза от того, чтобы оставить переменную неинициализированной? - PullRequest
8 голосов
/ 09 августа 2010

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

Например, в C ++ вы можете написать такой фрагмент кода:

int x;
cout << x;

Это, конечно, вернет непредсказуемые (ну, если вы не знали, как ваша программа отображала память), но мой вопрос: почему такое поведение разрешено компиляторам?

Существует ли какое-либо применение или эффективность, которая достигается за счет использования неинициализированной памяти?

edit : Мне пришло в голову, что предоставление инициализации пользователю может минимизировать число операций записи для носителей памяти, которые имеют ограниченный срок службы (циклы записи). Просто конкретный пример под вышеупомянутым заголовком «производительность». Спасибо.

Ответы [ 8 ]

13 голосов
/ 09 августа 2010

Мои мысли (и я раньше ошибался, просто спросите мою жену), что это просто пережиток более ранних воплощений языка.

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

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

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

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

int fn(void) {
    int x, y;
    /* Do some stuff to set y */
    x = y + 2;
    /* Do some more stuff */
}

В настоящее время я бы выбрал:

int fn(void) {
    int y;
    /* Do some stuff to set y */
    int x = y + 2;
    /* Do some more stuff */
}
4 голосов
/ 09 августа 2010

Некоторые API предназначены для возврата данных через передаваемые переменные, например:

bool ok;
int x = convert_to_int(some_string, &ok);

Он может устанавливать значение 'ok' внутри функции, поэтому инициализация его является пустой тратой.

(я не поддерживаю этот стиль API.)

4 голосов
/ 09 августа 2010

Самое старое оправдание в программировании: это повышает производительность!

edit: прочитайте ваши комментарии, и я согласен - много лет назад акцент на производительности был сделан на количестве циклов ЦП.Моим первым компилятором C был традиционный C (предшествовавший ANSI C), и он позволял компилировать все виды мерзостей.В наши дни производительность связана с количеством жалоб клиентов.Когда я говорю новым выпускникам, которых мы нанимаем, «мне все равно, как быстро программа дает неправильный ответ».Используйте все инструменты современных компиляторов и разработки, пишите меньше ошибок, и каждый может вернуться домой вовремя.

2 голосов
/ 09 августа 2010

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

например.

int x;
if (external_function() == 2) {
   x = 42;
} else if (another_function() == 3) {
   x = 49;
}
yet_another_function( &x );
cout << x;   // Is this a use-before-definition?

Хорошие компиляторывыдаст предупреждающее сообщение, если они обнаружат возможную ошибку use-before-initialize, но для сложных случаев - особенно с участием нескольких модулей компиляции - компилятор не сможет сказать.

Относительно того, должен ли языкдопустить концепцию неинициализированных переменных, это другое дело.C # немного необычен в определении каждой переменной как инициализируемой со значением по умолчанию.Большинство языков (C ++ / C / BCPL / FORTRAN / Assembler / ...) оставляют на усмотрение программиста вопрос о целесообразности инициализации.Хорошие компиляторы иногда могут обнаружить ненужные инициализации и устранить их, но это не само собой разумеющееся.Компиляторы для более непонятного оборудования, как правило, затрачивают меньше усилий на оптимизацию (что является трудной частью написания компилятора), поэтому языки, ориентированные на такое оборудование, как правило, не требуют ненужной генерации кода.

1 голос
/ 09 августа 2010

Некоторые языки имеют значения по умолчанию для некоторых типов переменных. При этом я сомневаюсь, что на любом языке есть преимущества в производительности, если их явно не инициализировать. Однако недостатки:

  • Возможность того, что он должен быть инициализирован, и без этого вы рискуете сбой
  • Неожиданные значения
  • Отсутствие ясности и цели для других программистов

Мое предложение всегда инициализировать ваши переменные, и согласованность окупится.

1 голос
/ 09 августа 2010

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

0 голосов
/ 09 августа 2010

для стиля цикла

int i;
for(i=0;i<something;++i){
    .......
}
do something with i

, и вы бы предпочли, чтобы цикл for выглядел как for(init;condition;inc)

вот тот, с абсолютной необходимостью

bool b;
do{
    ....
    b = g();
    ....
}while(!b);

горизонтальныйэкранная недвижимость с длинными вложенными именами

долгоживущая область видимости для отладки видимости

очень редко производительность

0 голосов
/ 09 августа 2010

В зависимости от размера переменной, оставление значения неинициализированным во имя производительности может рассматриваться как микрооптимизация. Относительно немногие программы (по сравнению с широким спектром типов программного обеспечения) будут отрицательно затронуты дополнительными двумя или тремя циклами, необходимыми для двойной загрузки; однако, предположим, что переменная была довольно большой, задержка инициализации, пока она не станет совершенно ясной, требуется инициализация, вероятно, хорошая идея.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...