Инициализация локальной переменной должна быть обязательной?

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

Таким образом, вы можете достичь этого с помощью 4 простых шагов:

1. Создайте каталог приложения как:

    -\resources (parent resource directory)
      -\menus (store all menus list constants)
      -\values
        -\app_strings.dart (store all strings constants)
        -\app_colors.dart  (store all colors constants)
        -\app_styles.dart  (store all styles i.e. material dark, light, cupertino etc.)
        -\app_dimens.dart  (store all dimension constants)

    -\components (parent component directory)
      -\your_custom_widget.dart(create custom component here)
      -\.....

    -\views
      -\your_view.dart(your view where you import custom component)

2. Создание констант ресурса:

Это очень простые шаги, так как вы должны добавлять только константы в соответствующие файлы ресурсов.

Пример - создание цветовых констант в app_colors.dart

import 'package:flutter/material.dart';

/// App Colors Class - Resource class for storing app level color constants
class AppColors {

  static const Color PRIMARY_COLOR = Color(0xFF35B4C5);
  static const Color PRIMARY_COLOR_LIGHT = Color(0xFFA5CFF1);
  static const Color PRIMARY_COLOR_DARK = Color(0xFF0D3656);
  static const Color ACCENT_COLOR = Color(0xFFF2DA04);
}

3. Создайте пользовательские компоненты:

Теперь в каталоге components создайте пользовательский виджет как:

class CustomWidget extends StatefulWidget{
   // Declare your widget parameters 
   final data-type your_parameter;
   .....
   .....
   .....

  // Create constant constructor 
  const CustomWidget(
    // Initialize all your widget parameters
    this.your_parameter
    .....
    .....
    .....)
  @override
  _CustomWidgetState createState() => _CustomWidgetState();
}


/// CustomWidget State class
class _CustomWidgetState extends State<CustomWidget>{
   // Here you should use existing widget from either material library or cupertino etc

    @override
    Widget build(BuildContext context) {
       return ExistingBaseWidget(
          // Set here all necessary parameters for customization
          // For setting constansts from resources you do it like this
          color : AppColors.COLOR_NAME,
          radius : AppDimens.BORDER_RADIUS,
          .......
       );
   }

}

4. Импортируйте пользовательский виджет в любые виды: В любые виды вы можете импортировать пользовательские виджеты, как использовать

child: CustomWidget(
       // Initialize all required parameters
       )

Преимущества

  1. [1120 ] В будущем, когда вы захотите изменить свои пользовательские виджеты или константы ресурсов, вам придется менять их только в одном месте, и они будут отражаться во всех местах.

  2. Также вы можете использовать эти пользовательские виджеты и константы ресурсов во всех ваших проектах с незначительными изменениями.

  3. Код представлений выглядит более понятным и понятным.

11
задан Robert Gamble 12 November 2008 в 03:26
поделиться

17 ответов

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

Длинный ответ: Если Вы объявляете переменную в начале функции и не используете ее до позже, необходимо пересмотреть размещение переменной к максимально локальному объему. Можно затем обычно присваивать ему необходимое значение сразу же.

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

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

11
ответ дан 3 December 2019 в 01:30
поделиться

Просто вторичное наблюдение. Инициализации только ЛЕГКО оптимизированы на типах примитивов или при присвоении функциями константы.

a = нечто ();

a = foo2 ();

Не может быть легко оптимизирован, потому что нечто может иметь побочные эффекты.

Также выделения "кучи" перед временем могли бы привести к огромным хитам производительности. Возьмите код как

void foo(int x)

{

ClassA *экземпляр = новый ClassA ();

//... сделайте что-то не "экземпляр", связанный... если (x> 5) {

delete instance;

return;

}

//.. сделайте что-то, что использует экземпляр

}

На том случае просто объявите экземпляр как раз в то самое время, когда Вы будете использовать его, и инициализировать его только там. И не компилятор не Может оптимизировать это для Вас, так как у конструктора могут быть побочные эффекты, которые изменило бы переупорядочение кода.

править: Я перестал работать при использовании функции :P листинга кода

0
ответ дан 3 December 2019 в 01:30
поделиться

Я думаю, что это - в большинстве случаев плохая идея инициализировать переменные со значением по умолчанию, потому что это просто скрывает ошибки, которые легко найдены с неинициализированными переменными. Если Вы забываете получать и устанавливать фактическое значение или удалять получить код случайно, Вы, вероятно, никогда не замечаете его, потому что 0 во многих случаях рыночная стоимость. Главным образом намного легче инициировать те ошибки со значением>> 0.

Например:


void func(int n)
{
    int i = 0;

    ... // Many lines of code

    for (;i < n; i++)
        do_something(i);

Через какое-то время Вы собираетесь добавить некоторый другой материал.


void func(int n)
{
    int i = 0;

    for (i = 0; i < 3; i++)
        do_something_else(i);

    ... // Many lines of code

    for (;i < n; i++)
        do_something(i);

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

0
ответ дан 3 December 2019 в 01:30
поделиться

Как простой пример, можно ли определить то, что это будет инициализировано к (C/C++)?

bool myVar;

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

0
ответ дан 3 December 2019 в 01:30
поделиться

Иногда переменная используется для "собирания" результата более длинного блока вложенного ifs/elses... В тех случаях я иногда сохраняю переменную неинициализированной, потому что она должна быть инициализирована позже одним из условных переходов.

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

0
ответ дан 3 December 2019 в 01:30
поделиться

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

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

Это обманывает парней, которые могут позже поддержать Ваш код в размышление, что инициализация требуется. То небольшое нечто = 0; увеличит сложность кода. Кроме этого это - просто вопрос вкуса.

Если Вы, unnessesary инициализируют переменные через сложные операторы, это может иметь побочный эффект.

Например:

  float x = sqrt(0);

Может быть оптимизирован Вашим компилятором, если Вы удачливы и работаете с умным компилятором. С не так умный компилятор это может также привести к дорогостоящему и unnessesary вызову функции, потому что sqrt может - поскольку побочный эффект - установил errno переменную.

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

0
ответ дан 3 December 2019 в 01:30
поделиться

Да: всегда инициализируйте свои переменные, если у Вас нет очень серьезного основания не к. Если мой код не потребует конкретного начального значения, то я буду часто инициализировать переменную к значению, которое гарантирует явную ошибку, если код, который следует, будет взломан.

1
ответ дан 3 December 2019 в 01:30
поделиться

Всегда инициализируйте локальные переменные для обнуления, по крайней мере. Как Вы видели, нет никакой реальной производительности этого.

int i = 0;
struct myStruct m = {0};

Вы в основном добавляете 1 или 2 инструкции по сборке, если это. На самом деле много времени выполнения C сделают это для Вас на сборке "Выпуска", и Вы не будете изменять вещь.

Но Вы должны initalize это, потому что у Вас теперь будет та гарантия.

Одна причина не инициализировать имеет отношение к отладке. Некоторое время выполнения, например, MS CRT, инициализирует память с предопределенными и зарегистрированными шаблонами, которые можно определить. Таким образом, когда Вы льетесь через память, Вы видите, что память является действительно неинициализированной, и это не использовалось и сбрасывалось. Это может быть полезно в отладке. Но это во время отладки.

1
ответ дан 3 December 2019 в 01:30
поделиться

В C/C++ я полностью соглашаюсь с Вами.

В Perl, когда я создаю переменную, она автоматически помещается в значение по умолчанию.

my ($val1, $val2, $val3, $val4);
print $val1, "\n";
print $val1 + 1, "\n";
print $val2 + 2, "\n";
print $val3 = $val3 . 'Hello, SO!', "\n";
print ++$val4 +4, "\n";

Они все установлены на undef первоначально. Undef является ложным значением и заполнителем. Из-за динамического контроля типов, если я добавляю число к нему, оно предполагает, что моя переменная является числом и заменяет undef eqivilent ложным значением 0. Если я делаю строковые операции, ложная версия строки является пустой строкой, и этим автоматически заменяют.

[jeremy@localhost Code]$ ./undef.pl

1
2
Hello, SO!
5

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

 my($x, $y, $z);

:-)

 my $x = 0;
 my $y = 0;
 my $z = 0;
1
ответ дан 3 December 2019 в 01:30
поделиться

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

Однако это не было бы плохо, по-моему, для аннотирования того, что Вы знаете о ловушках, чем-то в способе

uninitialized time_t t;
time( &t );
2
ответ дан 3 December 2019 в 01:30
поделиться

Это принадлежит C++ только, но между этими двумя методами существует определенное различие. Давайте предположим, что у Вас есть класс MyStuff, и Вы хотите инициализировать его другим классом. Вы могли сделать что-то как:

// Initialize MyStuff instance y
// ...
MyStuff x = y;
// ...

То, что это на самом деле делает, вызвать конструктора копии x. Это совпадает с:

MyStuff x(y);

Это отличается, чем этот код:

MyStuff x; // This calls the MyStuff default constructor.
x = y; // This calls the MyStuff assignment operator.

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

2
ответ дан 3 December 2019 в 01:30
поделиться

Позвольте мне рассказать Вам историю о продукте, я продолжил работать в 1992 и позже что в целях этой истории мы назовем Stackrobat. Мне присвоили ошибка, которая заставила приложение отказывать на Mac, но не в Windows, о, и ошибка не была восстанавливаема надежно. Это приняло QA лучшее участие недели для предложения рецепта, который работал, возможно, каждый 10-й раз.

Это был ад, разыскивающий первопричину, так как фактический катастрофический отказ произошел много позже действия, которое сделало это.

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

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

То, что произошло, было то, что большую часть времени стек, оказалось, имел значения, которые были по-видимому мягки, если они были разыменованы. Другие времена значения вызвали бы приложение к ружью его собственная "куча", вынув приложение когда-то намного позже.

Я провел больше чем две недели, пытаясь найти эту ошибку.

Урок: инициализируйте своих местных жителей. Если кто-то лает производительность на Вас, покажите им этот комментарий и скажите им, что Вы провели бы две недели, работая представляющий код и устраняющий узкие места вместо того, чтобы иметь необходимость разыскать ошибки как это. Средства отладки и средства проверки "кучи" получили путь лучше, так как я должен был сделать это, но вполне откровенно они поправились для компенсации ошибок от плохих методов как это.

Если Вы не работаете на крошечной системе (встроенный, и т.д.), инициализация местных жителей должна быть почти бесплатной. ПЕРЕМЕСТИТЕСЬ/ЗАГРУЗИТЕ инструкции очень, очень быстро. Напишите код, чтобы быть твердыми и удобными в сопровождении сначала. Осуществите рефакторинг его, чтобы быть производительной секундой.

3
ответ дан 3 December 2019 в 01:30
поделиться

Это - яркий пример Преждевременной оптимизации, корень всего зла

Полная кавычка:

Нет сомнения, что чаша Грааля эффективности ведет для злоупотребления. Программисты тратят впустую огромное количество времени, думающее об или вызывающее беспокойство о, скорость некритических частей их программ, и эти попытки эффективности на самом деле оказывают сильное негативное влияние, когда отладку и обслуживание рассматривают. Мы должны забыть о маленькой эффективности, сказать приблизительно 97% времени: преждевременная оптимизация является корнем всего зла. Все же мы не должны отказываться от наших возможностей в этом критические 3%. Хороший программист не будет убаюкан в самодовольство таким обоснованием, он будет мудр для осторожного рассмотрения критического кода; но только после того, как тот код был определен.

Это прибыло от Donald Knuth., кто Вы собираетесь верить... своим коллегам или Knuth?
Я знаю, где мои деньги...

Возвращаться к исходному вопросу: "Мы должны ПЕРЕДАТЬ ПОД МАНДАТ инициализацию?"
Я формулировал бы его как так:

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

5
ответ дан 3 December 2019 в 01:30
поделиться

Я не уверен, необходимо ли "сделать их обязательными", но я лично думаю, что всегда лучше инициализировать переменные. Если цель приложения состоит в том, чтобы быть максимально трудной затем, C/C++ открыт с этой целью. Однако я думаю, что многие из нас были записаны время или два, не инициализировав переменную и предположив, что она содержит допустимое значение (например, указатель), когда она действительно не делает. Указатель с адресом нуля намного легче проверить на то, чем если бы он имеет случайный мусор от последнего содержания памяти в том конкретном местоположении. Я думаю в большинстве случаев, это больше не вопрос производительности, а вопрос ясности и безопасности.

4
ответ дан 3 December 2019 в 01:30
поделиться

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

struct stat s;
s.st_dev = -1;
s.st_ino = -1;
s.st_mode = S_IRWXU;
s.st_nlink = 0;
s.st_size = 0;
// etc...
s.st_st_ctime = -1;
if(stat(path, &s) != 0) {
   // handle error
   return;
}

WTF???

Обратите внимание, что мы обрабатываем ошибку сразу же, таким образом, нет никакого вопроса о том, что происходит, если статистика перестала работать.

3
ответ дан 3 December 2019 в 01:30
поделиться

Если Вы думаете, что инициализация избыточна, это. Моя цель состоит в том, чтобы написать код, который максимально по-человечески читаем. Ненужная инициализация смущает будущего читателя.

Компиляторы C становятся довольно хорошими в ловле использования unitialized переменных, таким образом, опасность этого теперь минимальна.

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

6
ответ дан 3 December 2019 в 01:30
поделиться

Производительность? В наше время? Возможно, назад, когда центральные процессоры достигли 10 МГц, это действительно имело смысл, но сегодня едва проблема. Всегда инициализируйте их.

1
ответ дан 3 December 2019 в 01:30
поделиться