2014-12-01 17 views
6

Con shared_ptr incluso in C++ 11, si potrebbe ottenere un ambiente semi-garbage-collected. L'uso (inflazionistico?) Presenta alcuni svantaggi?Svantaggi di shared_ptr

Potrei immaginare un modello di classe, in cui si crea una classe in cui si digita la classe alla fine come shared_ptr per abbreviare la sintassi.

///////////////// 
//// MyClass //// 
///////////////// 

#include <memory> 

class MyClass { 
public: 
    Myclass(); 
}; 

typedef std::shared_ptr<MyClass> SharedMyClass; 

/////////////////////// 
//// Example Class //// 
/////////////////////// 

class Example { 
public: 
    Example(): myClassObject(new MyClass()) {} 
private: 
    SharedMyClass myClassObject; 
}; 
+1

Correlati [Qual è l'overhead da shared_ptr che è thread-safe?] (Http://stackoverflow.com/q/25780826/1708801) –

+5

IMO, non utilizzare un typedef per un tipo già leggibile. Rende solo un altro nome per i tuoi lettori da imparare. – dlf

+0

Abbreviando è solo uno stile personale che mi piace, e segue una semplice convenzione – Matze

risposta

10

Naturalmente ci sono degli svantaggi: si richiede memoria aggiuntiva per mantenere un conteggio di riferimento, e ogni volta che si copia o distruggere un'istanza shared_ptr questo conteggio di riferimento deve essere incrementato e decrementato. Se il programma utilizza più thread, la manipolazione del conteggio dei riferimenti deve essere eseguita in modo thread-safe, che può aggiungere un sovraccarico aggiuntivo, la cui entità dipende dall'implementazione.

Indipendentemente dal fatto che questo sovraccarico abbia un impatto negativo o negativo sul programma in base ai dettagli del programma. Generalmente si dovrebbe usare solo std::shared_ptr per le risorse che devono essere veramente condivise, perché può essere in qualche modo arbitrario su quale oggetto avrà bisogno di durare. In altri casi, un singolo punto di controllo è solitamente più facile da mantenere perché si sa esattamente per quanto tempo ciascuna risorsa sarà viva.

Inoltre, è necessario essere consapevoli del fatto che std::shared_ptr non è una panacea per la gestione della durata dell'oggetto. In particolare, se si dispone di due oggetti ciascuno dei quali è uno std::shared_ptr all'altro, gli oggetti hanno proprietà ciclica e non verranno mai eliminati automaticamente a meno che non si interrompa il ciclo invocando reset() su uno di essi.

+0

E non dimenticare che 'shared_ptr' è un modello. Se usi 'shared_ptr's per molti tipi diversi, questo può sommarsi a una notevole quantità di codice. – dlf

+3

Per non parlare della possibilità di riferimenti circolari, che in realtà non sono risolti con 'std :: shared: ptr <>' _garbage collection_. –

+1

@dlf Infatti, anche se mi aspetto che un qualsiasi compilatore di ottimizzazione decente possa allineare quasi ogni funzione membro, in particolare 'operator *' e 'operator->' che sono probabilmente i più usati. – cdhowie

3

Un'altra cosa che vale la pena menzionare è che è necessario fare molta attenzione quando si progettano le API con std::shared_ptr.

L'ovvio vantaggio rispetto a un puntatore raw è la gestione automatica della memoria (con il possesso ciclico della proprietà) ma rimangono altri problemi/domande. Quando la risorsa è condivisa, stai abbandonando (in una certa misura) il controllo e la capacità di ragionare sul tuo codice.

Posso modificare l'oggetto dato che non potrei essere l'unico a trattenerlo?

Si modifica l'oggetto e la modifica si riflette sull'intero sistema. Più grande è il sistema, meno evidenti sono le implicazioni ed è più difficile dimostrare che è effettivamente sicuro. Sean Parent dice spesso che un ptr condiviso è in effetti buono come una variabile globale.

+0

Modificare i dati condivisi in un ambiente concorrente è comunque un odore di codice, 'shared_ptr' non lo rende migliore o peggiore di fare la stessa cosa senza' shared_ptr' –

+0

shared_ptr si occupa della durata dell'oggetto, non della concorrenza. Solo perché un puntatore viene tenuto in un shared_ptr non significa che l'oggetto puntato verrà toccato in più thread. –

+0

@JonathanWakely I dati condivisi potrebbero essere una coda thread-safe e l'operazione di modifica "aggiungi un elemento", il tutto è valido e comune. Il punto era che quando la risorsa è condivisa (non necessariamente attraverso 'std :: shared_ptr'), è più difficile verificare la correttezza dell'operazione, qualunque essa sia. –

1

I prestazioni sono importanti I wold non utilizzare std :: sahred_ptr. Ad esempio, per ordinare un array può con puntatori reali è 5 volte più veloce di ordinare con i puntatori condivisi.

D'altra parte il puntatore condiviso non evita tutti i problemi con perdite di dati inutili in caso di riferimenti circolari. Naturalmente, questo può essere risolto con weak_ptr, ma ciò che intendo è che anche quel puntatore condiviso deve essere gestito con cura.

Preferisco usare shared_ptr per elementi statici, perché gli elementi statici non vengono cancellati da un distruttore di una classe.