2012-02-14 9 views
5

Lettura di Alexandrescu e wikipipidia Vedo il pointee e il contatore di riferimento sono memorizzati nell'heap. Quindi si dice che il conteggio dei riferimenti è inefficiente dato che il contatore deve essere allocato sull'heap? Perché non è memorizzato nello stack?Perché le implementazioni del puntatore intelligente C++ mantengono il contatore di riferimento sull'heap insieme al punto di punta?

+0

Puoi mostrare un esempio di ciò che stai descrivendo? –

+0

In quale altro modo faresti? –

+0

Sia "contatore di riferimento" che "heap" sono semplici dettagli di implementazione.Il vero problema è che la semantica della proprietà condivisa può essere implementata solo con allocazione dinamica. –

risposta

9

Perché lo si perde non appena l'istanza corrente del puntatore intelligente esce dall'ambito.

Un puntatore intelligente viene utilizzato per simulare gli oggetti di archiviazione automatici allocati dinamicamente. I puntatori intelligenti sono gestiti automaticamente. Quindi, quando uno viene distrutto, anche tutto ciò che memorizza nella memoria automatica viene distrutto. Ma non vuoi perdere il contatore di riferimento. Quindi lo memorizzi nella memoria dinamica.

3

Non può essere archiviato nello stack perché in tal caso una copia dell'oggetto risulterebbe anche in una copia del conto, che annullerebbe il suo scopo.

1

Come altri hanno sottolineato, la pila non è un luogo adatto per mantenere il conteggio di riferimento perché l'oggetto può sopravvivere stack frame corrente (in questo caso il conteggio di riferimento andrebbe via!)

Vale la pena osservando che alcune delle inefficienze associate al mettere il conteggio dei riferimenti sull'heap possono essere superate memorizzandole "insieme" con l'oggetto stesso. In boost, questo può essere ottenuto utilizzando boost::make_shared (per shared_ptr's) o boost::intrusive_ptr.

1

Esistono diversi tipi di puntatori intelligenti, progettati per scopi diversi. Il puntatore di cui si sta parlando è un puntatore intelligente condiviso (std::shared_ptr), che aiuta a condividere la proprietà dell'oggetto da più punti. Tutte le copie di shared_ptr incrementano e decrementano la stessa variabile di conteggio, che viene posizionata nell'heap, in quanto deve essere disponibile per tutte le copie dello shared_ptr anche dopo la morte della prima copia.

Quindi, shared_ptr internamente mantiene due puntatori: all'oggetto e al contatore. Pseudocodice:

class SharedPointer<T> { 
public: 
// ... 
private: 
    T* obj; 
    int* counter; 
} 

A proposito, quando si crea oggetto con std::make_shared, l'attuazione può ottimizzare le allocazioni allocando memoria sufficiente per contenere sia il contatore e l'oggetto e poi costruire le side-by-side.

Questo trucco al suo estremo ci dà un modello di riferimento conteggio invadente: l'oggetto contiene internamente suo contatore e fornisce AddRef e Release funzioni di incremento e decremento esso. È possibile utilizzare il puntatore intelligente intrusivo , ad es. boost::intrusive_ptr, che utilizza questo macchinario e quindi non ha bisogno di allocare un altro contatore separato. Questo è più veloce in termini di allocazioni, ma richiede di iniettare il contatore alla definizione della classe controllata.

Inoltre, quando non hai bisogno di proprietà di condivisione oggetto e solo bisogno di controllare è vita (in modo che sia distrutta ottiene quando restituisce la funzione), è possibile utilizzare il scope puntatore intelligente: std::unique_ptr o boost::scoped_ptr. Non ha bisogno del contatore del tutto, in quanto esiste una sola copia di unique_ptr.

Problemi correlati