Con C ++ 17 , shared_ptr
può essere utilizzato per gestire un array allocato dinamicamente. L' shared_ptr
argomento template in questo caso deve essere T[N]
o T[]
. Quindi puoi scrivere
shared_ptr<int[]> sp(new int[10]);
Da n4659, [util.smartptr.shared.const]
template<class Y> explicit shared_ptr(Y* p);
Richiede: Y
deve essere un tipo completo. L'espressione delete[] p
, quando T
è un tipo di array o delete p
, quando T
non è un tipo di array, deve avere un comportamento ben definito e non deve generare eccezioni.
...
Note: Quando T
è un tipo di array, questo costruttore non deve partecipare alla risoluzione del sovraccarico a meno che l'espressione non delete[] p
sia ben formata e sia o T
sia U[N]
ed Y(*)[N]
è convertibile in T*
, sia T
sia
U[]
e Y(*)[]
sia convertibile in T*
. ...
Per supportare ciò, il tipo di membro element_type
è ora definito come
using element_type = remove_extent_t<T>;
È possibile accedere agli elementi dell'array utilizzando operator[]
element_type& operator[](ptrdiff_t i) const;
Richiede: get() != 0 && i >= 0
. Se T
è U[N]
, i < N
. ...
Note: quando T
non è un tipo di array, non è specificato se viene dichiarata questa funzione membro. Se viene dichiarato, non è specificato quale sia il suo tipo di ritorno, tranne che la dichiarazione (sebbene non necessariamente la definizione) della funzione deve essere ben formata.
Prima di C ++ 17 , nonshared_ptr
poteva essere utilizzato per gestire array allocati dinamicamente. Per impostazione predefinita, chiamerà l'oggetto gestito quando non vi saranno più riferimenti. Tuttavia, quando si assegna l'utilizzo è necessario chiamare e non per liberare la risorsa.shared_ptr
delete
new[]
delete[]
delete
Per utilizzare correttamente shared_ptr
un array, è necessario fornire un deleter personalizzato.
template< typename T >
struct array_deleter
{
void operator ()( T const * p)
{
delete[] p;
}
};
Creare shared_ptr come segue:
std::shared_ptr<int> sp(new int[10], array_deleter<int>());
Ora shared_ptr
chiamerà correttamente delete[]
quando si distrugge l'oggetto gestito.
Il deleter personalizzato sopra può essere sostituito da
la std::default_delete
specializzazione parziale per i tipi di array
std::shared_ptr<int> sp(new int[10], std::default_delete<int[]>());
un'espressione lambda
std::shared_ptr<int> sp(new int[10], [](int *p) { delete[] p; });
Inoltre, a meno che tu non abbia effettivamente bisogno di condividere la condivisione dell'oggetto gestito, a unique_ptr
è più adatto per questa attività, poiché ha una specializzazione parziale per i tipi di array.
std::unique_ptr<int[]> up(new int[10]); // this will correctly call delete[]
Modifiche introdotte dalle estensioni C ++ per i fondamenti della biblioteca
Un'altra alternativa pre-C ++ 17 a quelle sopra elencate è stata fornita dalla Specifica tecnica sui fondamenti della biblioteca , che è stata ampliata shared_ptr
per consentirgli di lavorare fuori dagli schemi per i casi in cui possiede una serie di oggetti. La bozza attuale delle shared_ptr
modifiche previste per questo TS è disponibile in N4082 . Queste modifiche saranno accessibili tramite lo std::experimental
spazio dei nomi e incluse <experimental/memory>
nell'intestazione. Alcune delle modifiche rilevanti a supporto shared_ptr
degli array sono:
- La definizione del tipo di membro element_type
cambia
typedef T element_type;
typedef typename remove_extent<T>::type element_type;
- Il membro operator[]
è stato aggiunto
element_type& operator[](ptrdiff_t i) const noexcept;
- A differenza della unique_ptr
specializzazione parziale per gli array, entrambi shared_ptr<T[]>
e shared_ptr<T[N]>
saranno validi ed entrambi risulteranno delete[]
chiamati sull'array di oggetti gestito.
template<class Y> explicit shared_ptr(Y* p);
Richiede : Y
deve essere un tipo completo. L'espressione delete[] p
, quando T
è un tipo di array, o delete p
, quando T
non è un tipo di array, deve essere ben formata, deve avere un comportamento ben definito e non deve generare eccezioni. Quando T
è U[N]
, Y(*)[N]
deve essere convertibile in T*
; quando T
è U[]
, Y(*)[]
deve essere convertibile in T*
; in caso contrario, Y*
sarà convertibile in T*
.
std::vector
. Dovresti fare attenzione a passare l'array in giro usando i riferimenti in modo da non farne copie. La sintassi per l'accesso ai dati è più pulita di shared_ptr e il ridimensionamento è molto semplice. E ottieni tutta la bontà STL se mai lo desideri.