Mit C ++ 17 , shared_ptr
kann verwendet werden , um eine dynamisch zugewiesenen Array zu verwalten. Das shared_ptr
Vorlagenargument muss in diesem Fall T[N]
oder sein T[]
. Also kannst du schreiben
shared_ptr<int[]> sp(new int[10]);
Ab n4659 [util.smartptr.shared.const]
template<class Y> explicit shared_ptr(Y* p);
Benötigt: Y
muss ein vollständiger Typ sein. Der Ausdruck delete[] p
, wenn T
es sich um einen Array-Typ handelt oder delete p
wenn T
es sich nicht um einen Array-Typ handelt, muss ein genau definiertes Verhalten aufweisen und keine Ausnahmen auslösen.
...
Anmerkungen: Wenn T
es sich um einen Array-Typ handelt, darf dieser Konstruktor nicht an der Überladungsauflösung teilnehmen, es sei denn, der Ausdruck delete[] p
ist wohlgeformt und T
ist U[N]
und Y(*)[N]
ist konvertierbar in T*
oder T
ist
U[]
und Y(*)[]
ist konvertierbar in T*
. ...
Um dies zu unterstützen, ist der Elementtyp element_type
jetzt definiert als
using element_type = remove_extent_t<T>;
Auf Array-Elemente kann mit zugegriffen werden operator[]
element_type& operator[](ptrdiff_t i) const;
Benötigt : get() != 0 && i >= 0
. Wenn T
ja U[N]
, i < N
. ...
Anmerkungen: Wenn T
es sich nicht um einen Array-Typ handelt, ist nicht angegeben, ob diese Elementfunktion deklariert ist. Wenn es deklariert ist, ist nicht angegeben, um welchen Rückgabetyp es sich handelt, mit der Ausnahme, dass die Deklaration (obwohl nicht unbedingt die Definition) der Funktion wohlgeformt sein muss.
Vor dem C ++ 17 , shared_ptr
konnte nicht dynamisch zugewiesenen Arrays verwalten verwendet werden. Standardmäßig shared_ptr
wird delete
das verwaltete Objekt aufgerufen , wenn keine Verweise mehr darauf vorhanden sind. Wenn Sie jedoch mit zuweisen, müssen new[]
Sie die Ressource aufrufen delete[]
und nicht delete
, um sie freizugeben.
Zur korrekten Verwendung shared_ptr
mit einem Array müssen Sie einen benutzerdefinierten Löscher angeben.
template< typename T >
struct array_deleter
{
void operator ()( T const * p)
{
delete[] p;
}
};
Erstellen Sie den shared_ptr wie folgt:
std::shared_ptr<int> sp(new int[10], array_deleter<int>());
shared_ptr
Wird jetzt korrekt aufgerufen, delete[]
wenn das verwaltete Objekt zerstört wird.
Der oben angegebene benutzerdefinierte Löscher kann durch ersetzt werden
die std::default_delete
teilweise Spezialisierung für Array-Typen
std::shared_ptr<int> sp(new int[10], std::default_delete<int[]>());
ein Lambda-Ausdruck
std::shared_ptr<int> sp(new int[10], [](int *p) { delete[] p; });
Außerdem unique_ptr
ist a für diese Aufgabe besser geeignet , es sei denn, Sie benötigen tatsächlich eine gemeinsame Verwaltung des verwalteten Objekts , da es eine teilweise Spezialisierung für Array-Typen aufweist.
std::unique_ptr<int[]> up(new int[10]); // this will correctly call delete[]
Änderungen, die durch die C ++ - Erweiterungen für Bibliotheksgrundlagen eingeführt wurden
Eine weitere Alternative vor C ++ 17 zu den oben aufgeführten wurde von der Library Fundamentals Technical Specification bereitgestellt , die erweitert wurde shared_ptr
, damit sie für den Fall, dass sie ein Array von Objekten besitzt, sofort einsatzbereit ist. Der aktuelle Entwurf der shared_ptr
für diesen TS geplanten Änderungen ist in N4082 zu finden . Auf diese Änderungen kann über den std::experimental
Namespace zugegriffen und in die <experimental/memory>
Kopfzeile aufgenommen werden. Einige der relevanten Änderungen zur Unterstützung shared_ptr
von Arrays sind:
- Die Definition des Elementtyps element_type
ändert sich
typedef T element_type;
typedef typename remove_extent<T>::type element_type;
- Mitglied operator[]
wird hinzugefügt
element_type& operator[](ptrdiff_t i) const noexcept;
- Im Gegensatz zur unique_ptr
teilweisen Spezialisierung für Arrays sind beide shared_ptr<T[]>
und shared_ptr<T[N]>
gültig und führen dazu, delete[]
dass das verwaltete Array von Objekten aufgerufen wird.
template<class Y> explicit shared_ptr(Y* p);
Benötigt : Y
muss ein vollständiger Typ sein. Der Ausdruck delete[] p
, wenn T
es sich um einen Array-Typ handelt oder delete p
wenn T
es sich nicht um einen Array-Typ handelt, muss wohlgeformt sein, ein genau definiertes Verhalten aufweisen und keine Ausnahmen auslösen. Wann T
ist U[N]
, Y(*)[N]
soll konvertierbar sein zu T*
; wann T
ist U[]
, Y(*)[]
soll konvertierbar sein zu T*
; Andernfalls Y*
ist konvertierbar in T*
.
std::vector
. Sie müssen vorsichtig sein, um das Array mithilfe von Referenzen weiterzugeben, damit Sie keine Kopien davon erstellen. Die Syntax für den Zugriff auf Daten ist sauberer als shared_ptr, und die Größenänderung ist sehr, sehr einfach. Und Sie erhalten alle STL-Güte, falls Sie es jemals wollen.