shared_ptr in un array: dovrebbe essere usato?

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’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 matrice, questo costruttore non deve partecipare alla risoluzione di sovraccarico a meno che l’espressione delete[] p sia ben formata e T sia U[N] e Y(*)[N] sia convertibile in T* , oppure T è U[] e Y(*)[] è convertibile in T* . …

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 . Se T è U[N] , i < N . ...
Note: quando T 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[] 

Modifiche introdotte dalle estensioni C ++ per i fondamentali delle biblioteche

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'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* ; altrimenti, Y* sarà convertibile in T* .

Un’alternativa possibilmente più semplice che potresti essere in grado di usare è shared_ptr> .