Condividi tramite


Durata degli oggetti e delle risorse (C++ moderno)

A differenza dei linguaggi gestiti, non dispone di garbage collection (GC), che rilascia automaticamente le risorse di memoria no-più utilizzati durante l'esecuzione di un programma C++.In C++, la gestione delle risorse è direttamente correlata alla durata dell'oggetto.Questo documento descrive i fattori che influiscono sulla durata degli oggetti in C++ e come gestirlo.

C++ non dispone di GC principalmente poiché esso non gestisce le risorse di memoria non.Solo i distruttori deterministici come quelli di C++ possono gestire le risorse di memoria e la memoria non ugualmente.GC dispone anche di altri problemi, come overhead più elevato nella memoria e della CPU e località.Ma universalità è un problema fondamentale non è possibile attenuare attraverso le ottimizzazioni intelligente.

Concetti

Un aspetto importante nella gestione della durata degli oggetti è l'incapsulamento — chiunque utilizza un oggetto non è necessario sapere quali risorse oggetto proprietario, o come eliminarle o anche se possiede tutte le risorse a tutti i.Deve eliminare l'oggetto.Il linguaggio C++ di base è progettato per garantire che gli oggetti vengono distrutti negli orari corretti, come i blocchi sono usciti, in ordine inverso di costruzione.Quando viene eliminato un oggetto, le basi e i membri vengono distrutti in un ordine particolare.La lingua Elimina automaticamente gli oggetti, a meno che non operazioni speciali come allocazione heap o della nuova posizione.Ad esempio, puntatori intelligenti come unique_ptr e shared_ptr, e i contenitori della libreria STL (Standard Template) come vector, incapsulare new/delete e new[]/delete[] in oggetti, che dispongono di distruttori.Ecco perché è così importante per l'utilizzo di puntatori intelligenti e contenitori STL.

Un altro importante concetto di gestione della durata: i distruttori.I distruttori incapsulano il rilascio della risorsa.(Tasto di scelta rapida comuni è RRID, distruzione è rilascio di risorse). Una risorsa è qualcosa che si ottiene dal "sistema" e necessario assegnare più avanti.La memoria è la risorsa più comune, ma esistono anche i file, socket, trame e altre risorse di memoria non. Proprietario"di una risorsa, significa che è possibile utilizzare quando è necessario ma è anche possibile per rilasciarlo quando si è terminato con esso.Quando un oggetto viene eliminato, il distruttore rilascia le risorse che di proprietà.

Il concetto finale è il DAG (grafico aciclico diretto).La struttura di proprietà in un programma costituisce un DAG.Nessun oggetto può essere proprietario di se stesso, ovvero che non è solo impossibili ma anche intrinsecamente senza significato.Ma due oggetti possono condividere la proprietà di un oggetto di terzo.Diversi tipi di collegamenti sono possibili in un DAG simile al seguente: A è un membro di B (B appartiene A), archivi c un vector<D> (C appartiene ciascun elemento D), negozi e un shared_ptr<F> (E condivide proprietario di F, possibilmente con gli altri oggetti), e così via.Fino a quando non sono presenti alcun ciclo e ogni collegamento di DAG è rappresentato da un oggetto che ha un distruttore (anziché un puntatore raw, handle o altro meccanismo), quindi perdite di risorse sono impossibili perché la lingua impedisce loro.Le risorse vengono rilasciate immediatamente dopo che non sono più necessari, senza un garbage collector in esecuzione.La durata di verifica è privo di sovraccarico per l'ambito dello stack, basi, membri e casi correlati ed economico per shared_ptr.

Hh438473.collapse_all(it-it,VS.110).gifDurata in heap

Per la durata dell'oggetto dell'heap, utilizzare puntatori intelligenti.Usa shared_ptr e make_shared il puntatore predefinito e l'allocatore.Usa weak_ptr per interrompere cicli, eseguire la memorizzazione nella cache e osservare gli oggetti senza influire o presupponendo che qualsiasi elemento sulla loro durata.

void func() {

auto p = make_shared<widget>(); // no leak, and exception safe
...
p->draw(); 

} // no delete required, out-of-scope triggers smart pointer destructor

Usa unique_ptr per la proprietà univoco, ad esempio, nel pimpl idioma.Per ulteriori informazioni, vedere Pimpl per l'incapsulamento della fase di compilazione (C++ moderno). Rendere un unique_ptr la destinazione primaria di tutto esplicita new le espressioni.

unique_ptr<widget> p(new widget());

È possibile utilizzare i puntatori non elaborati per non proprietario e di osservazione.Un puntatore non proprietario può penzolare, ma non subiscono una perdita.

class node {
  ...
  vector<unique_ptr<node>> children; // node owns children
  node* parent; // node observes parent, which is not a concern
  ...
};
node::node() : parent(...) { children.emplace_back(new node(...) ); }

Quando è necessaria l'ottimizzazione delle prestazioni, è necessario utilizzare e ben incapsulato proprietario puntatori e chiamate esplicite a eliminare.Un esempio è quando si implementa la propria struttura di dati a basso livello.

Hh438473.collapse_all(it-it,VS.110).gifDurata in stack

In C++ moderno, basato su stack ambito è un metodo efficace per scrivere codice efficiente poiché combina automatica durata dello stack e durata del membro di dati con grande efficienza-durata rilevamento è essenzialmente gratuito di overhead.Durata dell'oggetto dell'heap richiede la gestione manuale diligente e può essere l'origine delle perdite di risorse e le inefficienze, soprattutto quando si lavora con i puntatori non elaborati.Si consideri il codice che illustra l'ambito di stack:

class widget {
private:
  gadget g;   // lifetime automatically tied to enclosing object
public:
  void draw();
};

void functionUsingWidget () {
  widget w;   // lifetime automatically tied to enclosing scope
              // constructs w, including the w.g gadget member
  …
  w.draw();
  …
} // automatic destruction and deallocation for w and w.g
  // automatic exception safety, 
  // as if "finally { w.dispose(); w.g.dispose(); }"

Limitare l'uso della durata della statica (statica globale, locale statica di funzione) poiché possono verificarsi problemi.Cosa accade quando il costruttore di un oggetto globale genera un'eccezione?In genere, gli errori applicazione in modo che può essere difficile eseguire il debug.Ordine di costruzione è problematica per gli oggetti di durata statici e non è indipendente dalla concorrenza.Non solo è un problema di costruzione dell'oggetto ordine di distruzione può essere complessa, soprattutto nei casi in cui è coinvolto il polimorfismo.Anche se l'oggetto o variabile non polimorfica e non è complessa costruzione/eliminazione di ordinamento, è ancora il problema di concorrenza di thread-safe.Un'applicazione multithread non può modificare i dati in oggetti statici senza la necessità di archiviazione locale di thread, i blocchi di risorse e altre precauzioni speciali.

Vedere anche

Altre risorse

Digitare di nuovo a C++ (C++ moderno)

Riferimenti al linguaggio C++

Riferimento della libreria C++ standard