Лучшая практика при вызове инициализировать функции несколько раз? - PullRequest
2 голосов
/ 18 ноября 2010

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

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

void initialize() {
    initialized = true;
    pointer = new T;
}

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

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

Теперь, каков вообще «лучший» метод, который помогает сохранить мой код управляемым в будущем?

РЕДАКТИРОВАТЬ : спасибо за ответы до сих пор.Однако я хотел бы знать, как люди справляются с этим более общим способом.- Как люди обрабатывают «простые» ошибки, которые могут игнорироваться.(например, вызывать одну и ту же функцию дважды, тогда как это имеет смысл только 1 раз).

Ответы [ 6 ]

4 голосов
/ 18 ноября 2010

Вы единственный, кто действительно может ответить на вопрос: считаете ли вы, что initialize функция может в итоге быть вызвана дважды, или это будет означать, что ваша программа следовала неожиданному потоку выполнения?

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

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

2 голосов
/ 18 ноября 2010

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

Я бы просто пропустил код инициализации, если структура уже существует.

void initialize() {
    if (!initialized)
    {
      initialized = true;
      pointer = new T;
    }
}

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

0 голосов
/ 18 ноября 2010

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

Существует два типичных варианта использования:

  • По требованию / Ленивый экземпляр: если вы не уверены, что он будет использоваться и создавать его дорого, то лучше НЕ инициализировать его в конструкторе
  • Кэширование данных: для кэшированиярезультат потенциально дорогостоящей операции, так что последующие вызовы не должны вычислять ее еще раз

Вы находитесь в категории «Ленивый», и в этом случае проще использовать флаг или значение, допускающее обнуление:

  • комбинация флаг + значение: повторное использование существующего класса без выделения кучи, однако для этого требуется построение по умолчанию
  • интеллектуальный указатель: это обходит проблему построения по умолчанию за счет выделения кучи.Проверьте необходимую семантику копирования ...
  • boost::optional<T>: аналогично указателю, но с глубокой семантикой копирования и без выделения кучи.Требуется, чтобы тип был полностью определен, поэтому он тяжелее для зависимостей.

Я бы настоятельно рекомендовал идиому boost::optional<T>, или если вы хотите обеспечить изоляцию зависимостей, вы можете прибегнуть к интеллектуальному указателю, напримерstd::unique_ptr<T> (или boost::scoped_ptr<T>, если у вас нет доступа к компилятору C ++ 0x).

0 голосов
/ 18 ноября 2010

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

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

0 голосов
/ 18 ноября 2010

Я бы посмотрел на использование умных указателей boost или STL.

0 голосов
/ 18 ноября 2010

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

...