In C ++, quanto tempo dedicato al programmatore è dedicato alla gestione della memoria

39

Le persone che sono abituate ai linguaggi di raccolta dei rifiuti spesso hanno paura della gestione della memoria del C ++. Ci sono strumenti, come auto_ptr e shared_ptr , che gestiranno molte delle attività di gestione della memoria per te. Un sacco di librerie C ++ anticipano questi strumenti e hanno il loro modo di gestire le attività di gestione della memoria.

Quanto tempo dedichi alle attività di gestione della memoria?

Ho il sospetto che dipenda in larga misura dall'insieme di librerie che usi, quindi per favore indica quali sono le tue risposte e se lo fanno meglio o peggio.

    
posta Sean McMillan 03.10.2011 - 15:50
fonte

8 risposte

54

Il moderno C ++ non ti preoccupa della gestione della memoria fino a quando non lo devi, cioè fino a quando non hai bisogno di organizzare la tua memoria a mano, principalmente per scopi di ottimizzazione, o se il contesto ti costringe a farlo (pensa all'hardware a grandi vincoli) . Ho scritto interi giochi senza manipolare la memoria grezza, solo preoccupandomi di usare i contenitori che sono lo strumento giusto per il lavoro, come in qualsiasi lingua.

Quindi dipende dal progetto ma il più delle volte non è la gestione della memoria che devi gestire, ma solo la vita dell'oggetto. Questo è risolto usando puntatori intelligenti , ovvero uno strumento C ++ idiomatico derivante da RAII .

Una volta compreso RAII , la gestione della memoria non sarà un problema.

Quindi, quando avrai bisogno di accedere alla memoria non formattata, lo farai in un codice molto specifico, localizzato e identificabile, come nelle implementazioni degli oggetti pool, non "ovunque".

Al di fuori di questo tipo di codice, non dovrai manipolare la memoria, ma solo la durata degli oggetti.

La parte "difficile" è capire RAII.

    
risposta data 03.10.2011 - 15:59
fonte
32

La gestione della memoria è usata per spaventare i bambini, ma è solo un tipo di risorsa che un programmatore deve seguire. Pensa agli handle di file, alle connessioni di rete, alle altre risorse ottenute dal sistema operativo.

Le lingue che supportano la garbage collection di solito non ignorano solo l'esistenza di queste risorse, ma rendono anche più difficile gestirle correttamente non fornendo un distruttore.

Quindi, in breve, suggerirei che non si spenda gran parte del tempo di uno sviluppatore C ++ a preoccuparsi della gestione della memoria. Come risposta di klaim indica, una volta ottenuto un handle su RAII, il resto è solo di riflesso.

    
risposta data 03.10.2011 - 16:41
fonte
13

Praticamente niente. Anche vecchie tecnologie come COM, puoi scrivere deleteri personalizzati per i puntatori standard che li convertiranno in un tempo molto breve. Ad esempio, std::unique_ptr può essere convertito in modo univoco in possesso di un riferimento COM con cinque righe di un deleter personalizzato. Anche se devi scrivere manualmente il tuo gestore di risorse, la prevalenza di conoscenza come SRP e copy-and-swap rende relativamente facile scrivere una classe di gestione delle risorse da usare per sempre.

La realtà è che condivisioni, esclusività e non proprietà sono tutte fornite con il compilatore C ++ 11, e devi solo scrivere piccoli adattatori per farli funzionare anche con il vecchio codice.

    
risposta data 03.10.2011 - 15:57
fonte
11

Quando ero un programmatore C ++ (molto tempo fa), ho speso un molto tempo a preoccuparmi del bug di gestione della memoria quando cercavo di correggere i bug difficili da riprodurre .

Con il modem C ++, la gestione della memoria è molto meno problematica, ma puoi fidarti di tutti su un grande team per farlo bene. Qual è il costo / tempo di:

  • Formazione (non molti programmatori arrivano con una buona comprensione dei problemi)
  • Revisioni del codice per trovare i problemi di gestione della memoria
  • Debug dei problemi di gestione della memoria
  • Tenendo sempre presente che un bug in una parte dell'app, potrebbe essere dovuto a un problema di gestione della memoria in una parte non correlata dell'app .

Quindi non è solo il tempo che spendi " fare ", questo è più di un problema su grandi progetti.

    
risposta data 03.10.2011 - 17:11
fonte
2

Uso molto le librerie boost e TR1, e rendono la gestione della memoria in senso stretto (nuovo / cancella) un non-problema. D'altra parte, l'allocazione della memoria in C ++ non è economica, e bisogna prestare attenzione a dove questi fantasiosi puntatori condivisi vengono creati. Si finisce per utilizzare molto le aree di lavoro o si lavora con la memoria basata sullo stack. In generale, direi che è principalmente un problema di progettazione, non un problema di implementazione.

    
risposta data 03.10.2011 - 15:55
fonte
2

quanto tempo ci vuole come cliente? molto poco, una volta capito. quando un container gestisce la durata e i riferimenti, è davvero molto semplice. questo è molto più semplice del conteggio dei riferimenti manuali ed è praticamente trasparente se si considera il contenitore che si utilizza come documentazione che il compilatore impedisce in modo conveniente all'utente di eseguire trasferimenti di proprietà non validi in un sistema typesafe ben progettato.

la maggior parte delle volte che trascorro (come cliente) viene speso contenente tipi di altre API, quindi funzionano bene nel contesto dei tuoi programmi. esempio: questo è il mio contenitore ThirdPartyFont, e supporta queste funzionalità e implementa la distruzione in questo modo, facendo riferimento al conteggio in questo modo e copiando in questo modo e ... . Molti di questi costrutti devono essere installati, ed è spesso il posto logico dove metterli. se vuoi includerlo nel tempo o meno dipende dalla tua definizione (l'implementazione deve esistere quando si interfaccia con questi apis, comunque, giusto?).

dopodiché dovrai prendere in considerazione la memoria e la proprietà. in un sistema di livello inferiore, questo è buono e necessario, ma può richiedere un po 'di tempo e impalcature per implementare il modo in cui dovresti spostare le cose. non lo vedo come un dolore poiché questo è un requisito di un sistema di livello inferiore. proprietà, controllo e responsabilità sono evidenti.

così possiamo trasformarlo in apis basate su c che usano tipi opachi: i nostri contenitori ci permettono di astrarre tutti i piccoli dettagli di implementazione della gestione della vita e della copia di questi tipi opachi, il che rende la gestione delle risorse molto molto semplice e fa risparmiare tempo , difetti e riduce le implementazioni.

è davvero molto semplice utilizzarli - il problema (proveniente da GC) è che ora devi considerare le vite delle tue risorse. se ti sbagli, può volerci molto tempo per risolverlo. l'apprendimento e l'integrazione di una gestione a vita esplicita è comprensibilmente complesso nel confronto (non per tutte le persone): questo è il vero ostacolo. una volta che sei a tuo agio nel controllare le vite e utilizzare le buone soluzioni, allora è davvero molto facile gestire la vita delle risorse. non è una parte significativa della mia giornata (a meno che non si sia insinuato un bug difficile).

se non stai usando i contenitori (puntatore automatico / condiviso), allora stai solo pregando per il dolore.

ho implementato le mie librerie personali. ci vuole me per implementare queste cose, ma molte persone riutilizzano (che di solito è una buona idea).

    
risposta data 03.10.2011 - 17:02
fonte
1

Vuoi dire manualmente dover liberare memoria, chiudere file, cose di questo tipo? In tal caso, direi il minimo e in genere meno della maggior parte degli altri linguaggi che ho utilizzato, soprattutto se generalizziamo non solo la "gestione della memoria" ma anche la "gestione delle risorse". In questo senso, penso che il C ++ richieda una gestione delle risorse meno manuale rispetto a, ad esempio, Java o C #.

È principalmente dovuto ai distruttori che automatizzano la distruzione della risorsa (memoria o altro). In genere, l'unica volta che devo liberare / distruggere una risorsa manualmente in C ++ è se sto implementando una struttura di dati a livello di vlow (qualcosa che la maggior parte delle persone non ha bisogno di fare) o usando un'API C in cui passo solo un po 'di tempo avvolgere la risorsa C che deve essere manualmente liberata / distrutta / chiusa in un wrapper C ++ conforme a RAII.

Naturalmente se un utente richiede di chiudere un'immagine in un software di modifica delle immagini, devo rimuovere l'immagine da una raccolta o qualcosa del genere. Ma si spera che ciò non contenga una gestione "memoria" o "risorsa" di un tipo che conta in questo contesto, dal momento che è praticamente necessario in qualsiasi lingua se si desidera liberare la memoria associata a quell'immagine in quel momento. Ma di nuovo tutto ciò che devi fare è rimuovere l'immagine dalla raccolta e il distruttore di immagini si prenderà cura di tutto il resto.

Nel frattempo, se mi confronto, ad esempio, in Java o in C #, spesso trovi persone che devono chiudere i file manualmente, disconnettere manualmente i socket, impostare i riferimenti agli oggetti su null per consentire loro di raccogliere i dati inutili, ecc. C'è molto altro memoria manuale e gestione delle risorse in quelle lingue se me lo chiedi. In C ++ spesso non hai nemmeno bisogno di unlock di un mutex manualmente, dato che l'armadietto mutex lo farà automaticamente quando il mutex esce dallo scope. Ad esempio, non dovresti mai fare cose del genere in C ++:

System.IO.StreamReader file = new System.IO.StreamReader(path);
try
{
    file.ReadBlock(buffer, index, buffer.Length);
}
catch (System.IO.IOException e)
{
    ...
}
finally
{
    if (file != null)
        file.Close();
}

Non c'è bisogno di fare cose come chiudere i file manualmente in C ++. Finiscono per chiudersi automaticamente nell'istante in cui escono dal campo di applicazione, indipendentemente dal fatto che escono dallo scopo o da percorsi di esecuzione normali o eccezionali. Cosa simile per risorse relative alla memoria come std::vector . Tale codice come file.Close() di cui sopra sarebbe spesso disapprovato da quando, soprattutto nel contesto di un blocco finally , che suggerisce che la risorsa locale deve essere liberata manualmente quando l'intera mentalità attorno a C ++ è quella di automatizzarlo.

In termini di gestione manuale della memoria, direi che C richiede il massimo, Java / C # una quantità media e C ++ il minimo tra questi. Ci sono molti motivi per essere un po 'timidi nell'usare C ++ dato che è un linguaggio molto difficile da padroneggiare, ma la gestione della memoria non dovrebbe essere uno di questi. Al contrario, in realtà penso che sia una delle lingue più facili là fuori in questo aspetto.

Ovviamente C ++ ti permette di iniziare manualmente ad allocare memoria e invocare operator delete/delete[] per liberare manualmente la memoria. Permette anche di usare funzioni C come malloc e free . Ma si tratta di pratiche di codifica in stile antico che credo siano diventate obsolete molto tempo prima che la gente desse credito, dal momento che Stroustrup stava sostenendo RAII prima ancora di coniare il termine fin dall'inizio. Quindi non penso nemmeno che sia giusto dire che il "moderno C ++" automatizza la gestione delle risorse, perché questo doveva essere lo scopo di sempre. Non puoi praticamente ottenere un'eccezione, altrimenti la sicurezza. È solo che molti sviluppatori fuorviati durante i primi anni '90 hanno provato ad usare il C ++ come C con gli oggetti, ignorando spesso completamente la gestione delle eccezioni, e non avrebbe mai dovuto essere usato in quel modo. Se usi C ++ come è stato praticamente sempre pensato per essere usato, la gestione della memoria è totalmente automatizzata e generalmente non è qualcosa che devi gestire manualmente (o che dovresti gestire) molto.

    
risposta data 18.12.2017 - 04:09
fonte
0

Dipende dai lead tecnici senior del team. In alcune aziende (compresa la mia), non esiste un concetto chiamato poin intelligente. È considerato di fantasia. Quindi, le persone semplicemente inseriscono le eliminazioni ovunque e c'è un disco per la fissazione delle perdite di memoria ogni 2 mesi. La nuova ondata di istruzioni di cancellazione arriva ovunque. Quindi, dipende dalla compagnia e dal tipo di persone che ci lavorano.

    
risposta data 07.10.2011 - 00:58
fonte

Leggi altre domande sui tag