Solo una piccola domanda riguardante shared_ptr
.
È una buona pratica usare shared_ptr
puntare a un array? Per esempio,
shared_ptr sp(new int[10]);
Se no, allora perché no? Una delle ragioni di cui sono già a conoscenza è che non è ansible incrementare / decrementare shared_ptr
. Quindi non può essere usato come un normale puntatore a un array.
Con C ++ 17 , shared_ptr
può essere utilizzato per gestire un array allocato dynamicmente. L’argomento del modello shared_ptr
in questo caso deve essere T[N]
o T[]
. Quindi puoi scrivere
shared_ptr sp(new int[10]);
Da n4659, [util.smartptr.shared.const]
template
explicit shared_ptr(Y* p); Richiede:
Y
deve essere un tipo completo. L’espressionedelete[] p
, quandoT
è un tipo di array, odelete p
, quandoT
non è un tipo di array, deve avere un comportamento ben definito e non deve generare eccezioni.
…
Note: QuandoT
è un tipo di matrice, questo costruttore non deve partecipare alla risoluzione di sovraccarico a meno che l’espressionedelete[] p
sia ben formata eT
siaU[N]
eY(*)[N]
sia convertibile inT*
, oppureT
èU[]
eY(*)[]
è convertibile inT*
. …
Per supportare questo, il tipo di membro element_type
è ora definito come
using element_type = remove_extent_t;
Gli elementi dell’array possono essere accessibili utilizzando l’ operator[]
element_type& operator[](ptrdiff_t i) const;
Richiede:
get() != 0 && i >= 0
. SeT
èU[N]
,i < N
. ...
Note: quandoT
non è un tipo di matrice, non è specificato se questa funzione membro è dichiarata. Se è dichiarato, non è specificato quale sia il suo tipo di ritorno, tranne che la dichiarazione (anche se non necessariamente la definizione) della funzione deve essere ben formata.
Prima di C ++ 17 , non è stato ansible utilizzare shared_ptr
per gestire gli array allocati dynamicmente. Per impostazione predefinita, shared_ptr
chiamerà delete
sull'object gestito quando non rimarranno più riferimenti. Tuttavia, quando si assegna usando new[]
è necessario chiamare delete[]
, e non delete
, per liberare la risorsa.
Per utilizzare correttamente shared_ptr
con un array, è necessario fornire un deleter personalizzato.
template< typename T > struct array_deleter { void operator ()( T const * p) { delete[] p; } };
Creare il shared_ptr come segue:
std::shared_ptr sp(new int[10], array_deleter ());
Ora shared_ptr
chiamerà correttamente delete[]
quando distruggerà l'object gestito.
Il deleter personalizzato sopra può essere sostituito da
la specializzazione parziale std::default_delete
per i tipi di array
std::shared_ptr sp(new int[10], std::default_delete());
un'espressione lambda
std::shared_ptr sp(new int[10], [](int *p) { delete[] p; });
Inoltre, a meno che non sia effettivamente necessario condividere la condivisione dell'object gestito, un unique_ptr
è più adatto per questa attività, poiché ha una specializzazione parziale per i tipi di array.
std::unique_ptr up(new int[10]); // this will correctly call delete[]
Un'altra alternativa precedente a C ++ 17 rispetto a quelle sopra elencate è stata fornita dalla specifica tecnica sui fondamenti della libreria , che ha aumentato la funzione shared_ptr
per consentirgli di lavorare fuori dagli schemi per i casi in cui possiede una matrice di oggetti. La bozza corrente delle modifiche shared_ptr
previste per questo TS può essere trovata in N4082 . Queste modifiche saranno accessibili tramite lo spazio dei nomi std::experimental
e incluse nell'intestazione
. Alcune delle modifiche rilevanti per supportare shared_ptr
per gli array sono:
- La definizione del tipo di elemento element_type
cambia
typedef T element_type;typedef typename remove_extent
::type element_type;
- Viene aggiunto l' operator[]
membro operator[]
element_type& operator[](ptrdiff_t i) const noexcept;
- A differenza della specializzazione parziale unique_ptr
per gli array, sia shared_ptr
e shared_ptr
saranno validi e entrambi comporteranno la delete[]
chiamata sull'array gestito di oggetti.
template
explicit shared_ptr(Y* p); Richiede :
Y
deve essere un tipo completo. L'espressionedelete[] p
, quandoT
è un tipo di array, odelete p
, quandoT
non è un tipo di array, deve essere ben formata, deve avere un comportamento ben definito e non deve generare eccezioni. QuandoT
èU[N]
,Y(*)[N]
deve essere convertibile inT*
; quandoT
èU[]
,Y(*)[]
deve essere convertibile inT*
; altrimenti,Y*
sarà convertibile inT*
.
Un’alternativa possibilmente più semplice che potresti essere in grado di usare è shared_ptr
.