Избегайте использования метода инициализации

12

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

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

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

Одно из возможных решений Инициализация в конструкторе. Есть только указатель на объект в глобальной области видимости. Создайте реальный объект после загрузки DLL.

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

Это приемлемо?


источник
У меня была такая же проблема при создании объектов, связанных с OpenGL, которые должны быть созданы до существования контекста OpenGL, но должны содержать объекты, зависящие от OpenGL, такие как списки вызовов, текстуры и т. Д.
3
Глупый вопрос № 1: Почему конструктор объекта не может загрузить DLL, если она еще не загружена?
Джон Р. Штром
1
Приносим извинения за воскрешение старого вопроса, но если кто-то читает его в 2017 году, используйте call_onceв C ++ 11 . Проекты, которые еще не находятся на C ++ 11, должны изучить, как call_once реализован в C ++ 11 (сосредоточиться на том, какую проблему он решает, а затем как), а затем повторно реализовать его в своем (устаревшем) варианте C ++. Он нуждается в многопоточном безопасном примитиве синхронизации, состояние которого необходимо статически инициализировать (с постоянным значением). Обратите внимание, что компиляторы до C ++ 11 могут иметь другие особенности, которые должны быть выполнены.
rwong

Ответы:

7

Похоже, работа для виртуального прокси.

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

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

Шаблон прокси в Википедии

Как вам эта идея?

edalorzo
источник
Вы действительно не решаете много здесь. для каждого метода, добавленного в реальный объект, вам также необходимо добавить этот метод в прокси. Нет?
Это позволяет избежать проблемы запоминания вызова init. функции, но кажется, что каждая функция в прокси все еще должна проверить, загружен ли DLL-файл.
1
@Sriram теперь есть большая разница, используя прокси, вы ограничили обслуживание, связанное с проверкой DLL, одним классом: прокси. Клиентам этого класса вообще не нужно будет знать о проверке DLL. Поскольку большинство методов выполняют делегирование, я не вижу большой проблемы в том, чтобы реализовать интерфейс в реальной теме прокси. Другими словами, вы можете предотвратить создание реального субъекта, пока не убедитесь, что DLL была загружена, и тогда вам не нужно будет каждый раз проверять состояние DLL.
@edalorzo: в то время как идея хороша, проблема в том, что мы уже говорим о прокси, а ОП жалуется на необходимость проверять каждый метод своего прокси ...
Матье М.
4

Ничего полезного не происходит, если DLL еще не загружена; объект только генерирует ошибку. Это фатальная ошибка? Как обрабатывается ошибка?

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

Это похоже на работу для тестирования, а не для архитектурного дизайна. Не просто вернуть ошибку, assertчтобы она никогда не случалась.

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

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

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

Первое: избегайте глобальных объектов как вредителей, если их состояние никогда не изменяется (конфигурация).

Теперь, если вы застряли с этим, по каким-то причинам, есть несколько проектов, которые могут вам помочь.

Я пришел с двумя идеями:

  1. Используйте Фасад, чтобы загрузить DLL. Доступ к Объекту возможен только через Фасад, Фасад загружает DLL при создании и создает экземпляр Объекта одновременно.

  2. Используй прокси, но умный вид;)

Позвольте мне остановиться на втором пункте, так как я боюсь, что ответ @edalorzo , возможно, напугал вас:

// Private
static Object& GetObjectImpl() { static Object O; return O; }

// Public
static Object& GetObject() {
  Object& o = GetObjectImpl();
  assert(o.isInitialized() && "Object not initialized yet!");
  return o;
}

Теперь у вас есть только один чек.

Это также можно сделать с помощью умного указателя:

Pointer<Object> o;

Здесь вы только резервируете место для указателя, изначально нулевого, и только когда DLL загружена, вы фактически выделите объект. Все предыдущие обращения должны вызывать исключение (NullException: p?) Или завершать программу (чисто).

Матье М.
источник
1

Это сложный вопрос. Я чувствую, что архитектура может помочь с проблемой.

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

Одна вещь, которая приходит на ум, это то, что вам нужно инициализировать .dll. Программист должен предположить, что объект не будет надежно возвращаться в любом случае. Возможно, вы сможете воспользоваться этим ( bool isObjectLoaded() { return isInitialized; }), но вы обязательно получите больше отчетов об ошибках по вашим проверкам.

Я думал о синглтоне.

Если вы вызываете синглтон, он должен вернуть правильный объект, если он может получить его. Если он не может вернуть правильный объект, вы должны получить некоторое значение ошибки / nullptr / пустой базовый объект. Это не сработает, если объект может умереть от вас.

Также, если вам нужно несколько экземпляров объекта, вы можете использовать что-то вроде Factory.

Джо Планте
источник