2009-06-05 18 views
20

Nel C effettivo ++ standard realizzando collezioni rispondenti seguenti regole è difficile se non impossibile:unique_ptr - miglioramento importante?

  1. sicurezza eccezione,
  2. operazioni economiche interne (in contenitori STL reali: le operazioni sono copie),
  3. automatica gestione della memoria.

Per soddisfare (1), una raccolta non può memorizzare puntatori grezzi. Per soddisfare (2), una raccolta deve memorizzare puntatori grezzi. Per soddisfare (3), una raccolta deve memorizzare oggetti per valore.

Conclusione: i tre articoli sono in conflitto tra loro.

L'elemento (2) non sarà soddisfatto quando vengono utilizzati shared_ptr s quando una raccolta deve spostare un elemento, sarà necessario effettuare due chiamate: a un costruttore e a un distruttore. Non sono possibili enormi operazioni di copia/spostamento come memcpy().

Sono corretto che il problema descritto verrà risolto da unique_ptr e std::move()? Collezioni che utilizzano gli strumenti saranno in grado di soddisfare tutte le 3 condizioni:

  1. Quando una collezione sarà cancellato come un effetto collaterale di un'eccezione, chiamerà i distruttori s' unique_ptr. Nessuna perdita di memoria.
    • unique_ptr non richiede spazio aggiuntivo per contatore di riferimento; pertanto il suo corpo dovrebbe essere esattamente la stessa dimensione, come puntatore avvolto,
    • non sono sicuro, ma sembra che questo permette di spostare gruppi di unique_ptrs utilizzando memmove() operazioni analoghe (?),
    • anche se è impossibile, l'operatore std::move() consentirà di spostare ciascun oggetto unique_ptr senza effettuare le chiamate della coppia costruttore/distruttore.
  2. unique_ptr avrà la proprietà esclusiva di una determinata memoria. Nessuna perdita di memoria accidentale sarà possibile.

E 'vero? Quali sono gli altri vantaggi dell'utilizzo di unique_ptr?

+6

Se yopu voglia di scrivere un blog, non esitate a farlo - ma non qui. –

+3

@Neil: questa è una domanda concreta, il problema è con un ampio background che dovevo includere. È * utile *, ad esempio la risposta di James Hopkin, che le operazioni simili a memcopy() non sono state apportate alla bozza. In quale altro modo potrei chiedere di questo? Senza lo sfondo? Nessuno capirà! –

+2

Forse sarebbe stato meglio chiedere come "Quali sono i vantaggi di unique_ptr". Puoi sempre rispondere alla tua domanda. –

risposta

6

Sono completamente d'accordo. C'è finalmente un modo naturale di gestire gli oggetti allocati nell'heap.

In risposta a:

non sono sicuro, ma sembra che questo permette di spostare gruppi di unique_ptr s utilizzando memmove() operazioni analoghe,

c'era un proposal permettere questo , ma non è entrato nello standard C++ 11.

2

Sì, hai ragione. Vorrei solo aggiungere questo è possibile grazie ai riferimenti di valore R.

0

Questa domanda illustra il motivo per cui amo così tanto il Boehm garbage collector (libgc). Non c'è mai bisogno di copiare nulla per motivi di gestione della memoria, e infatti, la proprietà della memoria non deve più essere menzionata come parte delle API. Devi acquistare un po 'di RAM in più per ottenere le stesse prestazioni della CPU, ma puoi risparmiare centinaia di ore di tempo dei programmatori. Tu decidi.

+9

I tempi di pausa su Boehm GC sono orribili. Anche Java è migliore. – Zifre

+0

Penso che l'idea qui sia di stare lontano dai netturbini. –

2

Quando una raccolta verrà eliminata come effetto collaterale di un'eccezione, chiamerà i distruttori di unique_ptr. Nessuna perdita di memoria.

Sì, un contenitore di unique_ptr soddisferà questo.

unique_ptr non richiede spazio aggiuntivo per il contatore di riferimento; quindi il suo corpo dovrebbe essere esatto delle stesse dimensioni, come puntatore avvolto

unique_ptr la dimensione è definita dall'implementazione. Mentre tutte le implementazioni ragionevoli di unique_ptr utilizzando il suo distruttore predefinito sarà probabilmente solo un puntatore di dimensioni, non vi è alcuna garanzia dello standard nello standard.

non sono sicuro, ma sembra che questo permette di spostare gruppi di unique_ptrs utilizzando memmove() operazioni analoghe (?),

non

Assolutamente. unique_ptr non è una classe banale; pertanto, non può essere memmove d in giro. Anche se lo fosse, non si possono semplicemente usare memmove, perché è necessario chiamare i distruttori per gli originali. Dovrebbe essere un memmove seguito da un memset.

anche se non è possibile, l'operatore std :: move() consente di spostare ciascun oggetto unique_ptr senza effettuare le chiamate della coppia costruttore/distruttore.

Anche errato. Il movimento non obbliga i costruttori e i distruttori a non essere chiamati. Gli unique_ptr che vengono distrutti devono essere distrutti; ciò richiede una chiamata ai loro distruttori. Allo stesso modo, i nuovi unique_ptr s devono chiamare i loro costruttori; è così che inizia la vita di un oggetto.

Non c'è modo di evitarlo; è come funziona C++.

Tuttavia, non è quello di cui dovresti preoccuparti. Onestamente, se sei preoccupato per una semplice chiamata costruttore/distruttore, sei nel codice che dovresti ottimizzare a mano (e quindi scrivere il tuo codice per), o stai prematuramente ottimizzando il tuo codice. Ciò che importa non è se vengono chiamati costruttori/distruttori; ciò che conta è la velocità del codice risultante.

unique_ptr avrà la proprietà esclusiva della memoria data. Nessuna perdita di memoria accidentale sarà possibile.

Sì, lo sarà.

Personalmente, direi che si sta facendo uno dei seguenti modi:

  • Essere eccessivamente paranoico circa la copia di oggetti. Ciò è dimostrato dal fatto che tu consideri che mettere un shared_ptr in un contenitore sia troppo costoso per una copia. Questa è una malattia fin troppo comune tra i programmatori C++. Questo non vuol dire che copiare è sempre buono o qualcosa del genere, ma l'ossessione di copiare uno shared_ptr in un contenitore è ridicolo al di fuori di circostanze eccezionali.

  • Non è a conoscenza di come utilizzare correttamente la semantica del movimento. Se i tuoi oggetti sono costosi da copiare ma economici da spostare ... quindi spostali nel contenitore. Non c'è motivo di avere un puntatore indiretto quando gli oggetti contengono già riferimenti indiretti al puntatore. Usa semplicemente il movimento con gli oggetti stessi, non gli unique_ptr s sugli oggetti.

  • Ignorare le alternative. Vale a dire, Boost's pointer containers. Sembrano avere tutto ciò che vuoi. Possiedono puntatori ai loro oggetti, ma esternamente hanno semantica del valore piuttosto che semantica del puntatore. Sono eccezionalmente sicuri, e qualsiasi copia avviene con i puntatori. No unique_ptr costruttore/distruttore "overhead".