Newsgroup: it.comp.lang.c++
Titolo: problema con libreria dinamica funzione che legge un stringa da console

Salve.
Ho fatto una piccola libreria statica, e ora volevo convertirla in
dinamica (con il vc++ 6.0)
La libreria dinamica funziona bene, tranne una funzione. questa
funzione
si chiama leggi_da_console() e legge un'intera stringa da console. La
funzione funziona, ma
alla fine del programma il programma lancia un errore di asserzione
fallita. L'asserzione
è chiamata dal distruttore della classe string. Riporto il codice:
SVG_API void leggi_da_console(std::string& s,char delim/*=\n*/) {
	//delim è per defaul \n
	char c[1024];
	cin.getline(c,1024,delim);
	s+=c;
}
//nel file prova.cpp, dentro al main
//dopo aver incluso i vari header e il .lib
cout<<"inserisci una stringa ";
string temp;
leggi_da_console(temp)
cout<<"\n hai inserito ";
cout<<endl;
system("pause");
reutnr 0;//il return del main
}//del main, qui lancia l'eccezione
Come vi ho detto, l'eccezione viene lanciata dal distruttore della
classe string che cerca
di distruggere la stringa temp (in cui ho memorizzato i dati inseriti
dall'utente );
questa è l'uncia funzione della libreria dinamica che non funziona. Ho
fatto della prove e
le altre funzionano, quindi non può essere un problema della libreria.
Facendo il debug, è
spuntato fuori che l'asserzione fallita viene lanciata in questa riga
//un file del vc++
* If this ASSERT fails, a bad pointer has been passed in. It may be
* totally bogus, or it may have been allocated from another heap.
* The pointer MUST come from the 'local' heap.
*/
_ASSERTE(_CrtIsValidHeapPointer(pUserData));//qua lancia l'asserzione
che fallisce
Qualcuno potrebbe aiutarmi, per favore? 
infinitamente grato

 leggi_da_console(temp)
la tua funzione accoda il contenuto dell'array locale c[1024], o 
la parte di esso sino a null, all'oggetto passato byref.
L'oggetto che gli passi è non inizializzato, quindi non ha 
memoria allocata. E' possibile anzi probabile che la funzione 
membro di concatenazione assegnamento allochi dinamicamente 
quanto basta, ma hai controllato in ogni caso che lo faccia 
davvero ? E' solo un mio dubbio, non sono esperto della STL.
ciao
Soviet_Mario


> }
Non si può allocare memoria in un modulo e liberarla in un altro.
la riga [ s += c; ]
alloca memoria in string nel modulo della dll.
Questa memoria viene poi liberata nel modulo principale al termine dello 
scope della string.
Una soluzione può essere quella di passare un buffer già allocato, anziché 
una string.

 alloca memoria in string nel modulo della dll.
il problema è quindi connesso con una cosa simile ma non uguale 
a quanto avevo intuito. Però non capisco bene la tua frase : 
perché la DLL non può allocare la memoria se trattasi di oggetto 
a life-time dinamico, e soprattutto filtrato da un metodo della 
classe string ? Forse la DLL non viene compilata includendo lo 
header della classe string ?
ciao
soviet_mario



Il problema di fondo è che la dll può essere richiamata tramite 
linguaggi/ambienti diversi e che la memoria può essere allocata in vari 
modi.
Il fatto che l'oggetto sia a life-time dinamico non c'entra.
Il problema è che non usa un buffer fisso per contenere la stringa, ma lo 
crea e ridimensiona secondo necessità.
E questa allocazione avviene nella dll. Poi, al termine del main avviene la 
distruzione dell'oggetto e, conseguentemente, la liberazione della memoria. 

 ha scritto nel messaggio 
news:433f8de4$0$32459$4faf...@reader1.news.tin.it...

ho ritrovato questo pezzo che descrive il comportamento
<cite>
Both the DLL and the executable file (EXE) maintain their own lists of 
allocated memory blocks, which they maintain through the malloc memory 
allocator. The C++ new and delete functions also rely on these lists of 
memory blocks, so that C++ tends to use dynamic memory allocation more often 
than C. If the DLL allocates some memory-for example, for the creation of a 
new instance of a class-this memory is marked in the allocation list of the 
DLL. If the EXE tries to free this memory, the run-time library looks 
through its list of allocated memory blocks and fails (usually with a GP 
fault). Thus, even if the memory between the DLL and the EXE is completely 
shared, the logic for managing allocation breaks if two modules mix their 
allocation schemes.
</cite> 

logicMind ha scritto:

molto interessante, salvo il thread : forse la conoscenza di ciò 
potrà essermi utile.
Ritenevo che chiamare un metodo della classe comportasse 
eseguire una chiamata "far" esterna alla DLL (dentro codice 
della libreria stringa del chiamante, l'EXE). In effetti se la 
DLL è compilata essa stessa linkando, come a posteriori pare 
legittimo, il modulo stringa, la chiamata è "near", interna, e 
quindi, come spiega il tuo testo, l'appartenenza della risorsa è 
attribuita al modulo dove sta il codice che alloca e non tanto 
al proprietario dell'istanza.
grazie
ciao
Soviet_Mario


Dove sta scritto che non puoi allocare memoria in una DLL e deallocarlo 
nell'eseguibile chiamante oppure o addirittura in un'altra DLL ?
Il problema e' un'altro. La DLL che hai creato e l'eseguibile che la 
utilizza DEVONO utilizzare la stessa libreria run-time del C (MSVCRTxxx.DLL)
Le funzioni 'new' e 'delete' del C++ utilizzano a loro volta la 'malloc()' e 
'free()' del C.
Queste ultime due funzioni sono esportate dalla libreria run-time del C con 
associata gestione della memoria heap.
Se nella DLL utilizzi una versione della libreria a run-tme (es. debug + 
single thread), la DLL creata utilizzera' il gestore dell'heap associato e 
se il tuo eseguibile utilizza una versione della libreria a run-tme diversa 
(es. debug + multi thread) avrai un altro gestore dell'heap. Hai dunque 
all'interno del tuo eseguibili 2 gestori dell'healp che nulla sanno l'uno 
dell'altro. Quando liberi la memoria allocata dalla DLL, il gestore 
dell'heap del tuo eseguibile (che presumo in debug mode) esegue un controllo 
(CrtIsValidHeapPointer()) per verificare se il puntatore passato e' stato 
allocato da lui stesso. Non trovandolo nella lista dei blocchi che ha 
allocato, viola la ASSERT() e genera un errore. Detto questo ricordo che 
siamo OT in questo newsgroup
Ciao
Fabio 

 ha scritto nel messaggio 
news:dhqs92$vl6$1...@nnrp-beta.newsland.it...

<ooo>
Non so se il messaggio è arrivato o è andato perso (nell'altra postazione ho 
dei problemi).
Lo riposto.
</ooo>
Concordo sull'OT, ma permettimi di risponderti.
Stai dicendo la stessa cosa che dico io.
La memoria deve essere liberata nello stesso modulo in cui è stata allocata.
Che poi si chiami runtime del C o pippo non cambia nulla.
Se stai sviluppando una dll non puoi sapere come e da chi verrà utilizzata.
Quindi, se allochi memoria nella dll, devi fornire un mezzo per poterla 
rilasciare. Non puoi contare sul fatto che chi la usi linki
dinamicamente il runtime (io, ad esempio, spesso lo linko staticamente per 
evitare che su macchine vecchie compaia il classico msvcrXX.dll mancante), 
oltre al fatto di dover rilasciare anche la versione di debug della dll.
Detto questo, per me si può chiudere qui.
Saluti 

 oltre al fatto di dover rilasciare anche la versione di debug della dll.
Questo e' un altro discorso; in questo caso effettivamente non si puo'
contare sul fatto che chi chiama usi lo stesso gestore di memoria ed e'
quindi indispensabile separare correttamente gli ambiti.
Questi argomenti esulano certamente dallo standard C++, ma non sono
specifici degli strumenti Microsoft, ne della piattaforma Windows.
Trattati in termini generali li considererei quasi "In Topic".
Ciao,
Nicola

Grazie a tutti per le vostre risposte. Grazie a voi ho risolto (ho
messo Multithread DLL sia nella Dll che nell'eseguibile).
arrivederci