Eu tenho esse código existente onde eles têm uma classe e um método de inicialização nessa classe. Espera-se que, uma vez que o objeto da classe seja criado, eles precisem chamar a inicialização.
Razão pela qual o método de inicialização existe O objeto é criado cedo para ter um escopo global e, em seguida, o método de inicialização é chamado posteriormente após o carregamento de uma dll da qual depende.
Problema ao inicializar A classe agora possui esse bool isInitialized, que precisa ser verificado em todos os métodos antes de prosseguir e retornar erro se não for inicializado. Simplificando, é uma grande dor.
Uma solução possível Inicialize no construtor. Tenha apenas um ponteiro para o objeto no escopo global. Crie o objeto real após o carregamento da DLL.
Problema com a solução acima Qualquer pessoa que crie um objeto dessa classe precisa saber que precisa ser criada somente após o carregamento da DLL, caso contrário, falhará.
Isso é aceitável?
call_once
C ++ 11 . Projetos que ainda não estão no C ++ 11 devem estudar como o call_once é implementado no C ++ 11 (foco no problema que ele resolve e depois como) e, em seguida, reimplementá-lo no seu sabor (obsoleto) de C ++. Ele precisa de uma primitiva de sincronização segura multithread, cujo estado precisa ser inicializado estaticamente (com um valor constante). Observe que os compiladores anteriores ao C ++ 11 podem ter outras idiossincrasias que precisam ser satisfeitas.Respostas:
Parece um trabalho para um proxy virtual.
Você pode criar um proxy virtual contendo uma referência ao objeto em questão. Enquanto a DLL não estiver carregada, o Proxy poderá oferecer um certo comportamento padrão aos clientes; assim que a DLL for carregada, o proxy simplesmente encaminhará todas as solicitações para o assunto real.
O proxy virtual será responsável por verificar a inicialização da DLL e, com base nisso, decide se a solicitação deve ser delegada ao assunto real.
Padrão de proxy na Wikipedia
Como você gosta dessa ideia?
fonte
Nada útil ocorre se a DLL ainda não estiver carregada; o objeto gera apenas um erro. É um erro fatal? Como o erro é tratado?
Sua metodologia de teste garante que esse erro nunca ocorra no produto acabado?
Parece um trabalho para testes, não para projetos de arquitetura. Não basta retornar um erro,
assert
pois isso nunca acontece.Corrija todos os clientes da classe que atualmente capturam e ignoram o erro para não tentar causá-lo em primeiro lugar.
Um padrão multithread pode ser definir uma variável de condição compartilhada após o carregamento da DLL e aguardar o construtor do objeto (e bloquear outros threads) até que a DLL seja carregada.
fonte
Primeira coisa: evite objetos globais como pragas, a menos que seu estado nunca mude (configuração).
Agora, se você estiver preso, por qualquer motivo, existem vários projetos que provavelmente podem ajudá-lo.
Eu vim com duas idéias:
Use uma fachada para carregar a DLL. O objeto só pode ser acessado através da fachada, a fachada carrega a DLL na criação e instancia o objeto ao mesmo tempo.
Use um proxy, mas o tipo inteligente;)
Deixe-me explicar o segundo ponto, pois temo que a resposta de @edalorzo possa ter assustado você:
Agora você tem apenas uma verificação.
Isso também pode ser feito através de algum tipo de ponteiro inteligente:
Aqui você reserva apenas espaço para um ponteiro, inicialmente nulo, e somente quando a DLL é carregada você realmente aloca o objeto. Todos os acessos anteriores devem gerar uma exceção (NullException: p?) Ou encerrar o programa (corretamente).
fonte
Esta é uma pergunta complicada. Eu sinto que a arquitetura pode ajudar com o problema.
A partir das evidências, parece que o .dll não é carregado quando o programa é carregado. Parece quase um plugin.
Uma coisa que vem à mente é que você precisa inicializar a DLL. O programador deve assumir que o objeto não retornará de maneira confiável, de qualquer maneira. Você pode tirar proveito disso (
bool isObjectLoaded() { return isInitialized; }
), mas definitivamente obterá mais relatórios de erros nas suas verificações.Eu estava pensando em um singleton.
Se você chamar o singleton, ele retornará o objeto correto se puder recuperar um. Se ele não puder retornar o objeto correto, você deverá obter algum valor de erro / nullptr / objeto base vazio. Isso não funcionaria se o objeto pudesse morrer em você.
Além disso, se você precisar de várias instâncias do objeto, poderá usar algo como um Factory.
fonte