Non ti manca nulla. Tuttavia, vorrei sottolineare qualcosa che non penso che nessuna delle altre risposte abbia affrontato chiaramente. La raccolta dei rifiuti riguarda innanzitutto la correttezza e la sicurezza del programma; la convenienza è secondaria (sebbene sia molto conveniente).
Se il programmatore gestisce la memoria manualmente, commettere un errore significa corrompere lo stato del programma. Il programma continua ma l'esecuzione non è più disponibile e non ha più alcun significato . Potrebbe fallire catastroficamente subito, ma probabilmente continuerà ad andare in un modo apparentemente corretto ma molto sottilmente sbagliato, probabilmente per giorni o settimane prima che qualcuno si accorga del problema. Ancora peggio è che i bug di memoria potrebbero essere sfruttati dagli aggressori. Se il programma buggy viene eseguito con i privilegi di amministratore e il bug consente a un utente malintenzionato di eseguire codice arbitrario, il potenziale di danno è quasi illimitato. Questo tipo di bug è molto difficile da rilevare e impossibile da evitare; prima o poi introdurremo un bug di memoria perché siamo tutti umani. Un linguaggio che esclude completamente la gestione manuale della memoria è garantito privo di questo tipo di bug (anche se i bug di memoria non sono sicuramente l'unico modo per introdurre una vulnerabilità di sicurezza.)
La mancanza di garbage collection preclude generalmente strutture di oggetti complicate. Per la maggior parte sei limitato alla creazione di oggetti che esistono sempre o che hanno un singolo proprietario che è responsabile della loro eliminazione. Ciò esclude, ad esempio, strutture dati persistenti , perché qualsiasi nodo dato potrebbe essere condiviso da molti oggetti e non esiste un modo affidabile di gestirlo. L'utilizzo di puntatori intelligenti con il conteggio dei riferimenti non è una soluzione: le loro prestazioni sono errate e i riferimenti cylic (due oggetti che si indicano l'un l'altro) non verranno liberati. Puoi introdurre riferimenti deboli per evitare il secondo problema, ma ora hai reso la gestione manuale della memoria ancora più difficile da ottenere (e le prestazioni sono ancora negative). La garbage collection consente a queste complicate strutture di dati di essere ripulite correttamente e in modo efficiente.
Ironicamente, la mancanza di strutture di dati persistenti rende il programma più difficile da ragionare, perché le modifiche alla struttura dei dati sono distruttive e ora devi stare molto attento a chi ha dei riferimenti e chi sta apportando modifiche ad esso. Quindi, oltre ai bug di memoria, devi preoccuparti anche di altri bug di stato / aliasing.