Newsgroup: it.comp.lang.c++
Titolo: utilizzo puntatore ad una classe in una Dll

Salve, ho un dubbio utilizzando una Dll.
Esistono queste classi:
classe IInterfaccia
{
  ...
}
e
classe Implementazione : public Interfaccia
{
  ...
}
Ho costruito una Dll dove ho crea la mia classe Implementazione.
Ho anche implementato un funzione che mi ritorna il puntatore 
all'istanza della classe Implementazione 
[.dll]
 ...
 Implementazione oggetto;
 Interfaccia *GetInstance()
 {
  return ( &oggetto );
 }
Ora dalla mia applicazione uso:
 IInterfaccia *AI =  ( chiamo GetInstance() della Dll caricata );
 e utilizzo:
 AI->Init();
 AI->Get( ... );
Il mio dubbio è  sapere se è lecito utilizzare il puntatore ottenuto 
tramite GetInstance() per chiamare le varie funzioni.
Grazie 
Massimo

 
Allora in generale direi di NO.
Però se DLL e app sono compilate dallo stesso compilatore funziona (o 
meglio con il MIO compilatore (MSVC) funziona). (in effetti è una 
tecnica che a volte utilizzo).
Con compilatori diversi potrebbe non funzionare come minimo per colpa 
delle diverse ABI.
Devi stare attento ad alcuni dettagli:
ad esempio non si può fare delete dalla app di un puntatore che proviene 
da un new della dll e viceversa.
di conseguenza devi stare all'occhio con qualsiasi roba che passa avanti 
e indietro tra app e dll
Ciao
GM

 indietro tra app e dll
Falso. Dipende se gli allocatori sono diversi, ma compilare 
l'applicazione per averli diversi è come indossare un giubbotto 
esplosivo con il timer attivato.
-- 
partecipa anche tu:  
http://www.beppegrillo.it/vaffanculoday/

 
Con Falso quale parte intendi?
 >> ad esempio non si può fare delete dalla app di un puntatore che
 >> proviene da un new della dll e viceversa.
oppure
 >> di conseguenza devi stare all'occhio con qualsiasi roba che passa
 >> avanti e indietro tra app e dll
Perchè se intendi la prima non direi che è falsa:
Stiamo parlando di dettagli molto platform depended, ma visto che 
parliamo di dll, si suppone che siamo su win.
In questo caso la dll e la app possono molto tranquillamente avere heap 
diversi (qunidi new e delete non possono oltrepassare i confini del 
modulo). Ora su due piedi non ricordo i dettagli ma mi pare proprio che 
con compilatori MS basta linkare una CRT diversa tra dll e app e ecco 
serviti i casini.
Se invece intendi la seconda, mi pare una conseguenza diretta della 
prima, quindi non è falsa neppure questa.
Il fatto che citi gli allocatori, mi fa pensare che tu stia pensando 
(simpatico loop) ai container STL.
In questo caso non conosco a fondo i dettagli (e non so neppure se sono 
specificati dallo standard) ma mi pare che comunque anche gli allocatori 
stl si basino sotto sotto su malloc e free, quindi direi che in generale 
non è igenico passare roba stl tra moduli.
Ripeto questo IN GENERALE.
Perchè poi se sia app sia dll linkano la stessa CRT (MA DINAMCAMENTE!!!) 
potrebbe anche funzionare. (perchè se uno dei due linka CRT staticamente 
-> BOOM)
Ma in ogni caso IMHO il passaggio di "oggetti che maneggiano memoria" 
tra moduli rimane non propriamente "sicuro".
Ciao
GM

 casini.
Infatti si usa il link dinamico dello stesso tipo di CRT appunto per 
evitare questi casini. Il trucco è avere un solo allocatore di memoria 
condiviso. In 10 anni che programmo non ricordo di avere mai avuto 
problemi con programmi compilati "bene".
Ovvero se usi programmi di terze parti che non sai cosa fa è un conto, 
se usi dll fatte in azienda, tutto è sotto controllo.
Che l'intero thread fosse dipendente dalla piattaforma era ovvio dal 
titolo del thread, è quindi posso dire la questione degli Heap è altra 
cosa ancora. Sotto windows puoi creare quanti Heap vuoi, però te li 
gestisci te. Se la DLL e l'EXE si passano i riferimenti agli Heap ci 
fanno quello che vogliono.
P.S.
Esistono sei tipi di CRT con i compilatori Microsoft. Se uno non lo sa, 
è meglio che si metta un poco a studiare prima di mettersi a 
pasticciare con le dll. Non lo dico come critica a te. E' solo che le 
dll si ci può fare molto male se non si sa quel che si fa.


 
Questo è esattamente quello che ho detto quando mettevo in guardia l'OP 
dicendo:
 >Devi stare attento ad alcuni dettagli:
 >ad esempio non si può fare delete dalla app di un puntatore che 
 >proviene da un new della dll e viceversa.
 >di conseguenza devi stare all'occhio con qualsiasi roba che passa 
 >avanti e indietro tra app e dll
Il fatto che stando ben attenti a come sono fatte dll e app possa 
funzionare, non è una buona scusa.
Inoltre anche se in 10 anni non hai mai avuto problemi non sono proprio 
d'accordo con la tua disinvoltura: le DLL servono proprio a svincolare 
le parti e fidarsi dei dettagli interni (o ancora peggio di come è 
settato un compilatore) ritengo non sia sano.
Basta che domani il tuo progetto diventi abbastanza grande che ci 
lavorino diverse persone, e in diverso tempo che è abbastanza facile 
fare casini. (ad es ti ricompilano una dll con un compilatore più 
recente. Magari può pure funzionare ma ti fideresti?)
Tra l'altro guarda per esempio COM dove per poter gestire la memoria 
"intermodulo" hanno inserito un gestore di memoria indipendente dal CRT 
(CoTaskMemAlloc IMalloc e compagnia).
La regola che uso io è che ogni modulo alloca/dealloca la sua roba e 
resto convinto che sia una buona regola (senza parlare del fatto che 
diversamente ottieni pure un disegno che mi pare parecchio "sporco").
Qualcuno diceva "massima coesione, minimo accoppiamento" riferito alle 
classi ma si applica a maggior ragione anche per i moduli.
Bene, già mi piace poco quando si passa la ownership della memoria tra 
classi, figuriamoci tra moduli. Questo non mi sembra proprio "minimo 
accoppiamento".
Per queste ragioni continuo a ritenere la mia frase riportata sopra 
sacrosanta.
GM

sacrosanta.
No, puoi dire che è una buona pratica, una pratica saggia. Ma non puoi 
dire che l'unica via. Non ci sono motivi tecnici per allocare in una 
dll, e disallocare in un altra dll. Per questo motivo io dico che la 
tua frase è falsa. Se vuoi, puoi. Se poi non vuoi, è un altro discorso.
Se tu hai problemi con questo approccio è un problema tuo, non una 
limitazione dell'accoppiata S.O. + compilatore. Il tuo metodo è 
"saggio" ma non seguirlo non è necessariamente "scorretto".


 
Neanche farlo apposta!
Uso la stessa tecnica esattamente nello stesso scenario:
ho un'interfaccia astratta a "frame grabber" e istanzio 
l'implementazione giusta con LoadLibrary.
La soluzione "pulita" sarebbe quella di scrivere un'interfaccia COM, ma 
in questo caso (stesso linguaggio, altissima correlazione tra i due 
pezzi) è più semplice il "COM casareccio" come hai già fatto.
Occhio ad un'altro dettaglio che può sfuggire:
in questo caso (se usi LoadLibrary) devi stare attento che il TLS 
automatico fornito dal compilatore non funziona correttamente. Cerca su 
msdn per i dettagli.
Poi basta che siamo OT e fra un po arriva qualcuno che ci taglia le 
gambine :)

 
No, si tratta di una pratica "borderline" che oggi forse va e domani non 
si sa. Che ad esempio non mi permette di debuggare solo uno dei due 
pezzi. Che in pratica non mi da una buona ROBUSTEZZA di fondo. Arriva un 
pischello nuovo, mi linka per sbaglio un CRT statico e crolla tutto.
GM

 Io combatto una guerra aziendale (persa) per azzerare l'uso delle DLL.
ricordo che è stato uno dei miei primi pensieri quando studiavo 
le API di .... Win_3.1 (oddio, che anno era ? 91-92 forse, azzo)
Ed è stata un'avversione durata molto a lungo, sin quando senza 
rendermene conto è sorta una specie di assuefazione rassegnata 
anche in me.
Da questo discorso probabilmente mi diramo un pochino, e chiedo 
scusa, ma riguarda la diatriba "filosofica" link statico vs. 
link dinamico.
Ebbene, anche da posizione sostanzialmente avversa al concetto 
della DLL (le ho usate solo quando ad es. non riuscivo a fare in 
VB una cosa che era elementare in C++, e quindi non avevo altro 
modo), un pregio glielo riconosco se l'O.S. e il programmatore 
le usano in modo saggio : un programma titanico, che come 
eseguibile standalone sarebbe gigantesco, può in effetti essere 
spezzato per risiedere solo parzialmente in ram. Ovviamente 
questo ha senso solo se uno non ha l'abitudine di fare il 
preaload di tutto l'esistente e scarica le DLL quando il 
programmone cambia contesto o modalità, e ha un costo (il load 
da disco reiterato).
Ma, ed ecco finalmente il dubbio dato che conosco pochissimo i 
compilatori recenti e medio recenti : è davvero l'unico sistema ?
Ricordo che addirittura l'antico Basic consentiva di caricare 
programmi a pezzi (si diceva OVERLAY all'epoca), per risparmiare 
memoria. Si può ancora fare ora come ora senza le DLL ?
Ci sono compilatori noti per fare questo ? Quali ? Lo fanno da 
sé o ci sono opzioni per suggerire che una porzione di codice o 
un modulo andrebbe, che so, non precaricato ma soltanto quando 
una sua funzione viene chiamata, e magari ci sono statement per 
lo scaricamento di codice (almeno i segmenti eseguibili, diciamo 
che coi dati la cosa può essere meno innocua).
Consigli e/o link ?
grazie
ciao
Soviet_Mario


spezzato per risiedere solo parzialmente in ram.
I sistemi operativi moderni si basano su memoria virtuale, quindi il
programmatore non deve piů occuparsi di questi dettagli. Per questo,
anche un eseguibile "gigantesco" non crea problemi.

 memoria.
Diciamo che tenendo conto di come funziona la gestione della memoria su
un sistema operativo moderno, la cosa rischia di essere semplicemente
senza senso. 
Nel mondo embedded e simili non mi pronuncio, tuttavia. Io parlo di
sviluppo su 'computer'.
-- 
blog:  
http://www.akropolix.net/rik0/blogs
 | Uccidete i filosofi,
site:  
http://www.akropolix.net/rik0/
      | tenetevi riso e
forum: 
http://www.akropolix.net/forum/
     | bacchette per voi.

 anche un eseguibile "gigantesco" non crea problemi.
data la banalità della presente risposta, rispondo insieme sia a 
te che a Mc Osten Franchi : effettivamente ho sollevato un 
problema totalmente obsoleto e che si può ormai annoverare tra 
l'archeologia del software.
Come giustamente avete entrambi fatto notare, il problema delle 
dimensioni di un eseguibile è stato ormai risolto a priori 
dall'OS stesso, sollevando il programmatore dalla necessità di 
sotterfugi vari da gestire manualmente.
Non ci avevo pensato nel formulare la domanda (il che è male !) 
e quindi non ho collegato i due aspetti.
Come corollario di ciò, direi che in effetti il concetto di DLL 
mi va sempre meno a genio !
ciao
Soviet_Mario

 funzione viene chiamata
Il GCC ti permette di ottimizzare il codice mettendo le funzioni 
statisticamente più usate "vicine" nel compilato. Con un sistema 
operativo decente avrai che quel che ti serve è caricato in memoria, 
mentre quello che non usi finisce nel disco di swap o nel page file.
Sono però argomenti "avanzati", prima di arrivarci bisogna far 
funzionare il programma :-)
