Newsgroup: it.comp.programmare.win32
Titolo: [C++] Incompatibilità fra Libreria Standard e Moduli DLL

Ho un problema di compatibilità che mi perseguita da più di un anno...
Se provo ad utilizzare la libreria standard del C++ all'interno di una DLL,
al 99.9% prima o poi ricevo un errore di "Debug Assertion Failed in file
DbgHeap.c [...]".
Ultimamente questo problema si verifica anche su codice scritto interamente
da me, e credo di averne individuato la causa: faccio new all'interno della
DLL e delete all'esterno. So che per principio non è per nulla un approccio
corretto alla programmazione Windows, e so anche bene che in genere è meglio
non ignorare le asserzioni... tuttavia se la ignoro il programma continua a
girare benissimo (al massimo ci sarà un pò di memory leak), ed IO MI SONO
SERIAMENTE ROTTO IL ç@§§# DI QUESTO PROBLEMA CHE MI PERSEGUITA DA UN ANNO!!!
Per quanto riguarda il codice scritto da me, potrei anche rimediare in
maniera da non dover deletare dall'esterno della DLL una variabile allocata
al suo interno (anche se questo mi costerebbe caro: le variabili in
questione sono eccezioni, e le lascio uscire dalla DLL (di tipo C++: esporto
le classi per intero) affinchè l'utente della DLL stessa possa gestire la
situazione di errore in base al contesto di chiamata... vorrà dire che le
dovrò passare per copia - approccio estremamente sconsigliabile!!!), MA COME
ME LA CAVO CON LA LIBRERIA STANDARD? Mi dà estrememente fastidio dovervi
rinunciare per un'asserzione che a prima vista non provoca nessun danno!!!
Vengo al dunque: avete anche voi problemi con questa asserzione maledetta?
Posso ignorarla senza conseguenze serie? O, ancora meglio, esiste qualche
Service Pack di Visual C++ 6.0 che elimina il problema? O, ancora ancora
meglio, esiste una maniera sicura di evitare il problema? Oppure (molto
molto peggio) devo definitivamente rinunciare alla libreria standard dentro
le DLL? Insomma... voi come vi siete comportat difronte al problema?
NOTA: Ripeto, a scanso di equivoci, che ignorare asserzioni non è una cosa
che gradisco, nè tantomeno mi piace fare operazioni illegali per Windows
(new nella DLL e delete fuori)... non sono un programmatore alla Machiavelli
(= il fine giustifica i mezzi): sono solo un programmatore molto seccato,
che vuole sapere se una volta tanto può fare un piccolo strappo alle regole
che il suo buon senso gli impone, o (meglio) se esiste una maniera sicura di
evitare il problema.

 ME LA CAVO CON LA LIBRERIA STANDARD?
Non uso la libreria standard del C++, ma e` presumibile che anche in
quel caso ci sia un modo per deallocare le eccezioni tramite una
funzione membro delle stesse, o in un modo similare.
--
Lorenzo

 Oppure potresti anche fare l'overloading dell'operatore delete.
Sì, mi sembra una buona idea... odio il "delete this" ma mi sà che è l'unica
soluzione... vedrò cosa riesco a fare... Tnx Lorenzo.

 libreria standard dentro le DLL?
dentro puoi usarla. Devi solo impedire che si veda da fuori perchè, per 
quanti accorgimenti tu possa inventarti, arriverà SEMPRE un programma a 
dimostrare la futilità dei tuoi sforzi con i più strani e difficilmente 
diagnosticabili errori. Il C++ non è pensato per l'interoperabilità. Io 
non esporterei mai classi C++ nude da una DLL, se non per uso interno o 
sotto minaccia di morte
-- 
  < 
http://www.reactos.com/
 >  Open source clone of Windows NT. Current
      Don't stand, REACT!      version 0.1.0. C, C++ and ASM developers
                               and beta testers are welcome!

 [...]
In effetti qui sono inqualificabile... classico discorso tipo "sò che bere
cherosene fà male alla salute, ma fin quando non mi viene il mal di
pancia...!!!"
Scrivendolo avevo la segreta speranza che qualcuno mi dicesse "in effetti è
un errore di <crtdbg.c>"... mi avrebbe tolto un peso dallo stomaco... vabbè,
capita a tutti di illudersi! C'è persino chi crede nella vita oltre la
morte! ;-P
In tutto il resto del post hai pienamente ragione... sei riuscita a
richiamarmi (in maniera un pò brusca - vedi sotto) all'ordine e al rigore
che ogni programmatore dovrebbe imporsi.
L'unica critica che ti faccio è... cavolo! potevi anche essere un pò più
soft! Mi hai subito etichettato come "l'incompetente scansafatiche" quando
io volevo soltanto sapere se esisteva qualche strada più semplice per
evitare il problema (tipo un Service Pack o una declspec), prima di mettermi
a modificare tutte le mie librerie!
Sai, non faccio (ancora) il programmatore per lavoro, e quando mi metto
davanti al compilatore lo faccio semplicemente per imparare qualcosa di
nuovo... in genere, per concentrarmi esclusivamente sull'argomento che stò
studiando, realizzo delle librerie da cui esporto funzioni e classi alla
menopeggio con declspec, solo per vedere se il codice funziona. Ora che mi
sono accorto che le mie librerie hanno raggiunto (dopo MOLTI sforzi) una
struttura (perlomeno interna) abbastanza robusta, ho cominciato a pensare
più seriamente al riutilizzo; ma prima di stravolgere le mie librerie volevo
esser sicuro che non ci fossero metodi più veloci e altrettanto sicuri.
Tutto qui!
Ora ho capito che gli approcci giusti sono COM e operator delete, ma ti
faccio notare che Lorenzo me li aveva già suggeriti con molte meno parole e
con molto più garbo. :-O
Riguardati le regole del buon postare! ;-P <== la faccina indica un tono
scherzoso

 Sai, non faccio (ancora) il programmatore per lavoro,
nemmeno io. Il C++ nemmeno lo conosco, vado principalmente a naso. Però 
ho studiato prima il C, e ho imparato ad essere paranoica riguardo alle 
funzioni esportate da DLL e all'allocazione dinamica della memoria, per 
quanto sedicenti "professionisti" cerchino di minimizzare


Innanzitutto spero che tu compili la DLL con la versione DLL della runtime
library :-)
Il problema della disallocazione della memoria allocata in una DLL è uno
degli errori + comuni dei programmatori Win32, quindi non fartene un
cruccio, non è nulla di strano :-)
Come problema nasce dal fatto che lo spazio d'indirizzo d'un processo
consiste d'un modulo EXE e di diversi moduli DLL. Alcuni di questi moduli
possono collegarsi ad una versione statica della libreria di run-time C/C++,
altri possono collegarsi ad una versione DLL della libreria. L'esistenza di
diverse versioni della libreria di runtime nello spazio d'indirizzo d'un
processo porta ai problemi che hai sperimentato, dato che
l'allocazione/disallocazione della memoria a seconda della versione è
trattata in modo differente (ovviamente).
Se sia l'EXE che la DLL si collegano alla libreria runtime C/C++ della DLL,
tutto funziona abbastanza bene, se invece uno o entrambi i moduli si
collegano alla versione statica della libreria, ecco che la disallocazione
non avrà + buon esito.
Il modo per risolvere questo problema è abbastanza semplice: basta seguire
la semplice regola che ogni modulo che offre una funzione per allocare della
memoria offra anche una funzione per disallocarla.
Esempio:
// Nell'eseguibile
VOID MyFunc() {
    PVOID pv = DLLAlloc(); // alloca la memoria
    ....
    DLLFree(pv); // la disalloca
}
// Nella DLL
PVOID DLLAlloc() {
    return(malloc(10));
}
BOOL DLLFree(PVOID pv)
{
    return(free(pv));
}
In questo modo il codice non darà mai errore. Ovviamente per new e delete il
discorso è il medesimo quando internamente richiamano free e malloc.

 [CUT]
Ringrazio per le spiegazioni :-)

 sbaglio?
Si sbagli, anche il C++ ha delle infrastrutture di linguaggio che
necessitano d'una libreria di runtime, esattamente come il C. Per entrambi i
linguaggi queste sono provvedute dal file MSVCRT(D).DLL e, nel caso del C++,
anche dal file MSVCPx0(D).DLL (dove x è la versione) per quel che riguarda i
componenti della STL.
Inoltre ti ricordo che il C++ incorpora il C come sottoinsieme e che cmq la
CRTLIB ha diverse funzioni, tra cui quella d'allocare ed inizializzare la
memoria per il thread primario, d'avviarlo, di passargli i parametri, di
gestirne la chiusura, etc, tutte cose necessarie anche in un programma C++.
Quando compili una DLL devi specificare al compilatore d'utilizzare la
versione DLL della CRTLIB, in Visual Studio da
Project->Settings->C/C++->Category: CodeGeneration.
Ciao :-)

Ho fatto un pò di esperimenti e FINALMENTE riesco ad utilizzare la libreria
standard del C++!!!
Il problema era, appunto, che utilizzavo la versione non-DLL della C/C++
RunTime Library.
Ti ringrazio: ho risolto pienamente i miei problemi
:-D :-D :-D :-D :-D :-D :-D :-D :-D :-D :-D :-D :-D :-D :-D :-D :-D :-D :-D
:-D :-D :-D :-D :-D
Tnx&byez - AG75202

Felice d'esserti stato d'aiuto :-)

Finalmente sono riuscito a risolvere entrambi i miei problemi, sia quelli
con allocazione/deallocazione di memoria, sia quelli con la libraria
standard.
Un ultimissima nota per Juliet (che cmq ringrazio per avermi fatto notare
che cercavo le mie soluzioni nella direzione sbagliata): per la questione
libreria standard la soluzione "facile e comoda" che io cercavo esisteva
davvero (vedi i post di Nuitari)!
In fondo mi sembrava strano che la M$ non avesse tenuto conto di una
limitazione (*) così grave delle DLL, e non avesse fornito una soluzione già
pronta!...
Ringrazio tutti quanti: non sapete quanto lavoro mi avete risparmiato!...
byez!
-----------------------------------------
(*): Uno degli scopi della libreria standard è proprio quello di fungere da
interfaccia comune per librerie distinte (potrei citare Stroustrup in "The
C++ Programming Language - 3rd Edition", pag. 430, ma andrei OT): se non
potesse essere utilizzata nelle DLL, che libreria standard sarebbe?