Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
C/C++ - Dubbio sulla gestione degli errori con throw/catch
Forum - C/C++ - Dubbio sulla gestione degli errori con throw/catch - Pagina 2

Pagine: [ 1 2 ] Precedente | Prossimo
Avatar
TheDarkJuster (Member)
Guru^2


Messaggi: 1620
Iscritto: 27/09/2013

Segnala al moderatore
Postato alle 22:02
Domenica, 23/08/2015
No, è passato troppo tempo da quando lo ho letto, ma credo si riferisse al fatto che alcuni sistemi hanno file di paging, partizioni di swap o sistemi simili.......
Ovviamente lo stack è unico, e le allocazioni da parte di malloc e new non sono fatte su stack, ma emulare l'heap è tutt'altro che impossibile...

PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 9:06
Lunedì, 24/08/2015
Son contento di vedere che anche se mi esprimo in modo sicuramente impreciso avevo in testa le cose corrette. I dubbi me li ha scatenati la frase che ho citato dalle dispense del corso, perché m'è sembrata un po' ambigua. Accertato che è solo una questione di fraintendimento di alcuni termini e che la memoria allocata dinamicamente non viene liberata per magia, ora sono ragionevolmente più sicuro (e un po' deluso, perché sarebbe stata una gradita scoperta). Grazie.

Tornando a new e malloc... da letture delle quali non so citare la fonte (molto probabilmente Guida al linguaggio C++ di H. Schildt) ricordo affermazioni che sostenevano che...

1. new e delete sono operatori, mentre malloc/calloc e free sono funzioni
2. new in pratica è un malloc/calloc che chiama il costruttore dell'oggetto creato subito dopo l'allocazione (malloc/calloc non chiama un bel niente, alloca e basta)
3. delete è in pratica un free che chiama il distruttore dell'oggetto prima di eliminarlo (free non chiama un bel niente, dealloca e basta)
4. bisogna evitare come la peste di usare free con un puntatore "ricevuto" da new e di usare delete su un puntatore ricevuto da malloc/calloc (questa non l'ho mai capita, anche se mi son sempre adeguato)
5. si possono usare new e malloc/calloc, così come free e delete, in uno stesso programma ma rispettando assolutamente 4.
6. se malloc/calloc fallisce restituisce NULL, mentre se new fallisce non è così (per questo prima di usare new inizializzo preventivamente e prudentemente tutti i puntatori su NULL)
7. non si deve usare free su un puntatore NULL, mentre è innocuo "cancellare" un puntatore NULL con delete (in effetti non succede nulla)
8. i puntatori ottenuti da NULL sono automaticamente del tipo corretto, quelli ottenuti da malloc/calloc sono dei puntatori "generici" di tipo *void (da cui la necessità del cast se si usano in contesto C++)

Ho elencato in ordine sparso, man mano che le cose mi venivano in mente, e avrò certamente lasciato fuori qualcosa. Al di là delle dimenticanze, è tutto esatto?

Insisto perché la gestione della memoria dinamica mi tiene sempre un po' sulle spine dal momento che dà luogo a problemi che vanno dal crash plateale a errori sottili e dagli effetti dilazionati ma a volte non meno gravi che per me non è così facile individuare. Insomma, lo ritengo un punto sul quale è bene essere più sicuri possibile.

Ah, la mia affermazione sul modo in cui Windows alla chiusura d'un processo "fa fuori" tutto quel che è stato lasciato indietro è corretta? Anche questo penso sia un punto importante, e la mia affermazione nel commento precedente era preceduta da quell'inquietante "per quel che ne so"...

Ultima modifica effettuata da AldoBaldo il 24/08/2015 alle 9:07


ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
PM Quote
Avatar
TheDarkJuster (Member)
Guru^2


Messaggi: 1620
Iscritto: 27/09/2013

Segnala al moderatore
Postato alle 12:54
Lunedì, 24/08/2015
Ok, questo codice viene direttamente dall'implementazione della runtime del c++ di clang/llvm:

Codice sorgente - presumibilmente C++

  1. _LIBCPP_WEAK _LIBCPP_NEW_DELETE_VIS
  2. void *
  3. operator new(std::size_t size)
  4. #if !__has_feature(cxx_noexcept)
  5.     throw(std::bad_alloc)
  6. #endif
  7. {
  8.     if (size == 0)
  9.         size = 1;
  10.     void* p;
  11.     while ((p = ::malloc(size)) == 0)
  12.     {
  13.         // If malloc fails and there is a new_handler,
  14.         // call it to try free up memory.
  15.         std::new_handler nh = std::get_new_handler();
  16.         if (nh)
  17.             nh();
  18.         else
  19. #ifndef _LIBCPP_NO_EXCEPTIONS
  20.             throw std::bad_alloc();
  21. #else
  22.             break;
  23. #endif
  24.     }
  25.     return p;
  26. }



La fonte è il repository svn di llvm: https://llvm.org/svn/llvm-project/libcxx/trunk/src/ (file new.cpp)

Ora sappiamo che llvm usa unmalloc (visual studio non si sa e la libc++ di g++ dovrei cercarla), che anche new ritorna void*, esattamente come malloc, e che l'unico motivo per cui delete su NULL non crasha è perchè viene fatto un controllo:

Codice sorgente - presumibilmente C/C++

  1. void
  2. operator delete(void* ptr) _NOEXCEPT
  3. {
  4.     if (ptr)
  5.         ::free(ptr);
  6. }



"4. bisogna evitare come la peste di usare free con un puntatore "ricevuto" da new e di usare delete su un puntatore ricevuto da malloc/calloc (questa non l'ho mai capita, anche se mi son sempre adeguato) "
Questo per due ragioni: non per tutti i compilatori la runtime è uguale a questa, e quindi allocano via malloc e liberano con free. E poi perchè se liberi un oggetto con free il distruttore non viene chiamato.

"si possono usare new e malloc/calloc, così come free e delete, in uno stesso programma ma rispettando assolutamente 4. "
Si ma è brutto.

"Ah, la mia affermazione sul modo in cui Windows alla chiusura d'un processo "fa fuori" tutto quel che è stato lasciato indietro è corretta? Anche questo penso sia un punto importante, e la mia affermazione nel commento precedente era preceduta da quell'inquietante "per quel che ne so"..."
http://stackoverflow.com/questions/1232262/memory-leak-in- ... il tizio che risponde alla persona che fa la domanda dice che vari sistemi operativi eliminano la memoria utilizzata dalla tua applicazione quando questa termina. Comunque la seconda risposta mi piace tantissimo: affidarsi al so affichè sia lui a rimediare ai tuoi memory leaks comporta due svantaggi: non sai se il so lo farà, perchè non è un comportamento standard, hai memoria inutilizzata e inallocabile durante l'esecuzione del tuo programma....

Ultima modifica effettuata da TheDarkJuster il 24/08/2015 alle 13:15
PM Quote
Avatar
TheDarkJuster (Member)
Guru^2


Messaggi: 1620
Iscritto: 27/09/2013

Segnala al moderatore
Postato alle 13:06
Lunedì, 24/08/2015
Vuoi che la memoria si liberi da solo all'uscita del tuo programma semplicemente chiamando un funzione? Bene:

copia operator new e chiamalo autoDeleteNew. Subito dopo aver allocato memoria copia il puntatore da ritornare in una lista di void e ritorna il puntatore.

A questo punto hai una lista (organizzala come vuoi: a stack, a vector, a doubly linked list, a linked list ecc....), sempre aggiornata con tutti gli indirizzi iniziali di tutti i blocchi di memoria allocata. Puoi usare questa lista per cancellare ricorsivamente tutta la memoria quando la suddetta funzione viene chiamata.

Altri bonus possono essere: 1. memorizzi anche la dimensione del blocco di memoria sulla lista, così puoi fare heapSizeOf() sul tuo puntatore e scoprire la lunghezza in byte. Ovviamente heapSizeOf è una funzione che devi definire tu.
2. copiare delete, cambiare il nome alla tua copia e fare in modo che quando della memoria viene eliminata viene rimossa dalla lista sopracitata.

Ecco, ora sai come aggiungere l'autodelete della memori allocata alla fine del programma. Ora poi sbizzarrirti a provare un po' di cose nuove :rotfl::rotfl::rotfl::D:D:rotfl::rotfl::rotfl:

PM Quote
Avatar
pierotofy (Admin)
Guru^2


Messaggi: 6230
Iscritto: 04/12/2003

Segnala al moderatore
Postato alle 15:11
Lunedì, 24/08/2015
Testo quotato

Postato originariamente da AldoBaldo:
Al di là delle dimenticanze, è tutto esatto?

Ah, la mia affermazione sul modo in cui Windows alla chiusura d'un processo "fa fuori" tutto quel che è stato lasciato indietro è corretta?



Si e si.


Il mio blog: https://piero.dev
PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 20:59
Lunedì, 24/08/2015
Grazie per le conferme, Piero.

TheDarkJuster, il metodo che hai descritto è intrigante, ma... ne vale la pena? Forse in programmi di dimensioni elefantiache, ma sicuramente non nelle piccole sciocchezze che metto insieme io. In ogni caso, sappi che ho preso nota e che prima o poi proverò a implementarlo. Se faccio esplodere qualche galassia a causa dei tuoi suggerimenti ti ritengo direttamente responsabile! :)


ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
PM Quote
Avatar
TheDarkJuster (Member)
Guru^2


Messaggi: 1620
Iscritto: 27/09/2013

Segnala al moderatore
Postato alle 23:10
Lunedì, 24/08/2015
Ok, se con l'auto deallocazione della memoria fai esplodere una galassia ti do il permesso di dare la colpa a me :D.
In pratica quello che ti ho consigliato di fare è un piccolissimo e inutile (ma estensibile)  garbage collector.

PM Quote
Avatar
lumo (Member)
Expert


Messaggi: 449
Iscritto: 18/04/2010

Segnala al moderatore
Postato alle 15:23
Mercoledì, 26/08/2015
Per gestire automaticamente la memoria in C++ idiomatico di solito si cerca di non allocarla con new, si usano i containers della STL che fanno da soli.
Se proprio bisogna allocare memoria (ad esempio per sfruttare il polimorfismo, metodi virtuali ecc) l'ultima tendenza è quella di usare i cosiddetti smart pointers (shared_ptr & company).

Riguardo a quanto detto prima su new, si può effettivamente creare un oggetto sullo stack usando il cosidetto "placement new": https://isocpp.org/wiki/faq/dtors#placement-new

E non bisogna mischiare free/malloc con new/delete perché non necessariamente gli ultimi usano internamente i primi (anzi, in genere si ridefiniscono proprio affinché usino un custom allocator, magari a sua volta basato su malloc).

PM Quote
Pagine: [ 1 2 ] Precedente | Prossimo