J'ai ce code existant où ils ont une classe et une méthode d'initialisation dans cette classe. Il est prévu qu'une fois l'objet de la classe créé, ils doivent appeler initialize dessus.
Raison pour laquelle la méthode initialize existe L'objet est créé tôt pour avoir une portée globale, puis la méthode initialize est appelée plus tard après le chargement d'une DLL dont elle dépend.
Problème avec l'initialisation La classe a maintenant ce bool isInitialized qui doit être vérifié dans chaque méthode avant de continuer et renvoie une erreur si elle n'est pas initialisée. Autrement dit, c'est une grande douleur.
Une solution possible Initialiser dans le constructeur. Ayez juste un pointeur sur l'objet dans la portée globale. Créez l'objet réel après le chargement de la DLL.
Problème avec la solution ci-dessus Quiconque crée un objet de cette classe doit savoir qu'il doit être créé uniquement après le chargement de la DLL, sinon il échouera.
Est-ce acceptable?
call_once
en C ++ 11 . Les projets qui ne sont pas encore en C ++ 11 devraient étudier comment call_once est implémenté en C ++ 11 (se concentrer sur le problème qu'il résout, puis comment), puis le réimplémenter dans leur version (périmée) de C ++. Il a besoin d'une primitive de synchronisation sécurisée multi-thread, dont l'état doit être initialisé statiquement (avec une valeur constante). Notez que les compilateurs pré-C ++ 11 peuvent avoir d'autres idiosyncrasies qui doivent être satisfaites.Réponses:
Cela ressemble à un travail pour un proxy virtuel.
Vous pouvez créer un proxy virtuel contenant une référence à l'objet en question. Bien que la DLL ne soit pas chargée, le proxy peut offrir un certain comportement par défaut aux clients.Une fois la DLL chargée, le proxy transmettra simplement toutes les demandes au sujet réel.
Le proxy virtuel sera chargé de vérifier l'initialisation de la DLL et en fonction de cela, décider si la demande doit être déléguée au sujet réel.
Modèle de proxy dans Wikipedia
Comment aimez-vous cette idée?
la source
Rien d'utile ne se produit si la DLL n'est pas encore chargée; l'objet ne génère qu'une erreur. Est-ce une erreur fatale? Comment l'erreur est-elle gérée?
Votre méthodologie de test garantit-elle que cette erreur ne se produit jamais dans le produit fini?
Cela ressemble à un travail de test, pas de conception architecturale. Ne vous contentez pas de renvoyer une erreur,
assert
cela n'arrive jamais.Corrigez tous les clients de la classe qui interceptent et ignorent actuellement l'erreur pour ne pas essayer de la provoquer en premier lieu.
Un modèle multithread peut être de définir une variable de condition partagée après le chargement de la DLL et de faire attendre le constructeur de l'objet (et de bloquer les autres threads) jusqu'à ce que la DLL soit chargée.
la source
Première chose: éviter les objets globaux comme nuisibles, à moins que leur état ne change jamais (configuration).
Maintenant, si vous êtes coincé avec cela, pour quelque raison que ce soit, il existe plusieurs modèles qui pourraient probablement vous aider.
J'ai eu deux idées:
Utilisez une façade pour charger la DLL. L'objet n'est accessible que via la façade, la façade charge la DLL lors de la création et instancie l'objet en même temps.
Utilisez un proxy, mais le type intelligent;)
Permettez-moi de développer le deuxième point, car je crains que la réponse de @edalorzo ne vous ait effrayé:
Maintenant, vous n'avez qu'un seul chèque.
Cela peut également être fait via une sorte de pointeur intelligent:
Ici, vous ne réservez que de l'espace pour un pointeur, initialement nul, et ce n'est que lorsque la DLL est chargée que vous allouerez réellement l'objet. Tous les accès précédents doivent déclencher une exception (NullException: p?) Ou terminer le programme (proprement).
la source
C'est une question délicate. Je pense que l'architecture peut aider à résoudre le problème.
D'après les preuves, il semble que le fichier .dll ne soit pas chargé lorsque le programme est chargé. Cela ressemble presque à un plugin.
Une chose qui me vient à l'esprit est que vous devez initialiser le fichier .dll. Le programmeur doit supposer que l'objet ne reviendra pas de manière fiable, de toute façon. Vous pourrez peut-être en profiter (
bool isObjectLoaded() { return isInitialized; }
), mais vous obtiendrez certainement plus de rapports de bogues lors de vos vérifications.Je pensais à un singleton.
Si vous appelez le singleton, il doit renvoyer l'objet correct s'il peut en récupérer un. S'il ne peut pas renvoyer l'objet correct, vous devriez obtenir une valeur d'erreur / nullptr / objet de base vide. Cela ne fonctionnerait pas si l'objet pouvait mourir sur vous, cependant.
De plus, si vous avez besoin de plusieurs instances de l'objet, vous pouvez utiliser quelque chose comme une usine à la place.
la source