2012-05-22 20 views
7

Ho avviato un progetto in C++. La gestione della memoria in questa lingua è nuova per me.C++ Gestione della memoria Tecniche/pratiche

Mi sono abituato a creare oggetti con new() e quindi a passare i puntatori e mentre funzionava, era un problema eseguire il debug e le persone mi guardavano in modo strano quando vedevano il codice. Sono abbastanza orgoglioso del fatto che non ha perdite o segfault (una volta risolto), ma è stato davvero un grande sforzo.

list <struct Connection *> users; 

struct Connection * accept_connection (const char *name) { 
    struct Connection * new_node = new Connection(); 
    new_node->_data = ... // whatever, set it up here 
    return new_node; 
} 

struct Connection * new_user = accept_connection (const char *name); 
users.append (new_user); 

Quindi ho una nuova strategia per questa prossima versione del progetto. Finora quello che sto facendo è creare oggetti con new() e assegnare loro un numero di ID intero univoco. Quindi immagazzino l'oggetto in una tabella con hash usando l'ID come chiave. Ora gli articoli sono memorizzati e passati in giro per il numero ID intero e quando è necessario de-referenziare, si passa alla tabella hash e si restituisce o thing * o NULL. Quindi non ho più errori di puntatore, ma la velocità del codice è leggermente ridotta.

typedef unsigned long ID_Number; 

// create a user and return the ID 
ID_Number create_user() { 
    ID_Number new_id = assign_unique_id(); 
    struct User * node = new User(); 
    node->_id = new_id; 
    node->_data = ... // whatever, set it up here 
    add_to_users_dict (new_id, node); 
    return new_id; 
} 

list <ID_Number> users; 

for_each (users.begin(), users.end(), process_user); 

void process_user (ID_Number i) { 
    struct User * u_ptr = lookup_user_dict (i); 
    if (u_ptr == NULL) { 
    // not found in dict 
    // somehow this guy was deleted 
    } else { 
    // we can do stuff with this guy 
    } 
} 

Ora sono una sorta di familiarità con i principi fondamentali della programmazione ma essendo un hobbista autodidatta Non ho familiarità con le pratiche e gli strumenti del settore. Quello che sto fondamentalmente chiedendo sono le linee guida sulla gestione della memoria:

1) Che cosa sto facendo giusto o sbagliato?

2) Esistono pacchetti o librerie che posso utilizzare per aiutarmi?

3) Quali sono le pratiche standard del settore?

4) Fondamentalmente cosa dovrei googling o comprare per kindle ecc?

Oggi io di solito uso Python, lo fa gestire un sacco di "back end" roba per me, ma ho bisogno di C o C++ (suppongo che sto utilizzando pianura C più i STDC++ librerie, io non sono abbastanza sicuro dove la sovrapposizione tra i linguaggi è - so solo che g ++ lo compila bene) per questo particolare progetto per motivi di velocità/prestazioni: sebbene sospetti che qualche genio matematico possa fornire correzioni algoritmiche che ne velocizzerebbero la fine, anche se questa è una domanda separata.

+2

Inizia guardando 'shared_ptr'. –

+0

Il primo strumento che utilizzerei è valgrind: http://valgrind.org/docs/manual/QuickStart.html – Anycorn

+10

Cerca RAII. Questo è un po 'folle. –

risposta

5

La migliore risposta che posso dare è che non dovresti usare i puntatori nel modo tradizionale. C++ 11 ha cambiato il modo in cui il programmatore si occupa della gestione della memoria.

Piuttosto che spiegare cose che sono già state spiegate in dettaglio da persone molto più intelligenti di me, fornirò solo alcuni collegamenti.

La prima si dovrebbe guardare è l'articolo di Herb Sutter Elements of Modern C++ Style Poi guarda il video da Bjarne Stroustrup C++11 Style

Se siete in grado di utilizzare il nuovo standard C++ 11 si dovrebbe, rende la gestione della memoria più più pulito di prima.

+2

E se non puoi usare C++ 11 (chiama il tuo headhunter!), C'è un sacco di cose per non gestire manualmente la memoria là fuori che funziona con C++ 03. –

1

1) Che cosa sto facendo giusto o sbagliato?

Non si utilizza l'idioma RAI (Resource Acquisition Is Initialization) o la semantica della proprietà C++ moderna.

2) Esistono pacchetti o librerie che posso utilizzare per aiutarmi?

Se è effettivamente necessario passare i puntatori in giro, è possibile utilizzare std :: unique_ptr e std :: shared_ptr. Ma prima di andare a quello dovresti imparare a far sì che i tuoi oggetti si comportino come proprietari di risorse con la semantica di RAII.

3) Quali sono le pratiche standard del settore?

4) Fondamentalmente cosa dovrei googling o comprare per kindle ecc?

RAII

2

Che cosa sto facendo giusto o sbagliato?

In sostanza, si è creato un sistema che utilizza le maniglie per fare riferimento agli oggetti anziché ai puntatori diretti. Questo può essere appropriato per alcuni scenari. I sistemi operativi utilizzano spesso handle quando il sistema operativo "possiede" l'oggetto e ne gestisce la durata, ma consente a un client di fare riferimento ad esso.

Esistono pacchetti o librerie che posso utilizzare per aiutarmi?

La libreria standard nel moderno C++ ha shared_ptr e unique_ptr, che sono puntatori intelligenti che gestiscono la durata degli oggetti dinamici. Sono un ottimo modo per usare RAII.

Quali sono le pratiche standard del settore?

Lo standard di fatto in C++ è RAII - l'allocazione delle risorse è l'inizializzazione. RAII lega l'assegnazione ai costruttori e la deallocazione ai distruttori. Dal momento che C++ ha solide garanzie su come e quando i giocatori e i responsabili eseguono, questo ti dà un modo perfetto per gestire le vite degli oggetti senza perdite. I puntatori intelligenti, shared_ptr e unique_ptr, rendono esplicita anche la proprietà dell'oggetto.

Fondamentalmente cosa dovrei googling o comprare per kindle ecc?

Cerca RAII.

1

Il tuo primo errore è utilizzare new.

memoria dinamica è raramente necessario, ed è ancora più rari è necessario "direttamente": oggetti allocati più dinamicamente vivono all'interno di un contenitore (come vector o map).

Il tuo secondo errore non è quello di utilizzare i costruttori, una volta capito che cosa sono invarianti di classe e come costruttori consentono loro, allora si sarà in grado di trarre vantaggio da RAII (Resource acquisizione è di inizializzazione) e smettere di codifica in C.

+0

Ho iniziato a guardare RAII - avvolgere il ctor/dtor in modo che il dtor venga chiamato automaticamente quando il wrapper viene rimosso dallo stack. Quindi con RAII come posso inserire una singola istanza di una cosa in due elenchi diversi? Dovrei usare i riferimenti? Come faccio quindi a interrompere la lista B dal iterare su una lista di cose che A ha detto di cancellare? Sembra che dovrei aggiungere un "is_deleted_skip_me" booleano in ogni struttura (e selezionarli periodicamente) o devo continuare a pulire i miei elenchi ogni volta che viene modificato un singolo elenco? - EDIT: inizio a pensare che l'applicazione sia progettata male se ha bisogno di così tante liste separate. – gecko

+0

@gecko: molte liste interdipendenti sembrano pessime, anche se non conosco i tuoi limiti. Non puoi copiare le informazioni in modo che ogni lista abbia la sua copia? Altrimenti, c'è sempre la possibilità di usare un 'shared_ptr', ma apre la porta ad alcune difficoltà lungo la strada. –

+0

Scatole (oggetto dati) all'interno di un contenitore (essa stessa un'istanza diversa della stessa struttura - solo il nome e la capacità differiscono), quindi il contenitore ha un elenco dei suoi contenuti. Un agente ricorda gli ultimi N elementi toccati. Quindi se un agente mette le scatole in un contenitore, questo è 2 liste con gli stessi oggetti. – gecko