Nur eine kleine Rückfrage bzgl shared_ptr
.
Ist es eine gute Praxis zu verwenden shared_ptr
auf ein Array zeigen? Zum Beispiel,
shared_ptr<int> sp(new int[10]);
Wenn nicht, warum nicht? Ein Grund, der mir bereits bekannt ist, ist, dass man die nicht erhöhen/verringern kann shared_ptr
. Daher kann es nicht wie ein normaler Zeiger auf ein Array verwendet werden.
Mit C++17, shared_ptr
kann verwendet werden, um ein dynamisch zugewiesenes Array zu verwalten. Die shared_ptr
Template-Argument muss in diesem Fall sein T[N]
oder T[]
. Sie dürfen also schreiben
shared_ptr<int[]> sp(new int[10]);
Von n4659, [util.smartptr.shared.const]
template<class Y> explicit shared_ptr(Y* p);
Erfordert: Y
muss ein vollständiger Typ sein. Der Ausdruck delete[] p
wann T
ist ein Array-Typ, oder delete p
wann T
ist kein Array-Typ, muss ein wohldefiniertes Verhalten haben und darf keine Ausnahmen auslösen.
…
Bemerkungen: Wann T
ein Arraytyp ist, darf dieser Konstruktor nicht an der Überladungsauflösung teilnehmen, es sei denn, der Ausdruck delete[] p
ist wohlgeformt und entweder T
ist U[N]
und Y(*)[N]
konvertierbar ist T*
oder T
ist
U[]
und Y(*)[]
konvertierbar ist T*
. …
Um dies zu unterstützen, der Mitgliedstyp element_type
ist jetzt definiert als
using element_type = remove_extent_t<T>;
Auf Array-Elemente kann über zugegriffen werden operator[]
element_type& operator[](ptrdiff_t i) const;
Erfordert: get() != 0 && i >= 0
. Wenn T
ist U[N]
, i < N
. …
Bemerkungen: Wann T
kein Array-Typ ist, ist nicht angegeben, ob diese Member-Funktion deklariert ist. Wenn sie deklariert ist, ist ihr Rückgabetyp nicht angegeben, außer dass die Deklaration (obwohl nicht unbedingt die Definition) der Funktion wohlgeformt sein muss.
Vor C++17, shared_ptr
könnten nicht verwendet werden, um dynamisch zugewiesene Arrays zu verwalten. Standardmäßig, shared_ptr
werde anrufen delete
auf das verwaltete Objekt, wenn keine Verweise mehr darauf verbleiben. Wenn Sie jedoch mithilfe von zuweisen new[]
du musst anrufen delete[]
und nicht delete
um die Ressource freizugeben.
Um richtig zu verwenden shared_ptr
Bei 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>());
Jetzt shared_ptr
wird richtig anrufen delete[]
beim Zerstören des verwalteten Objekts.
Der benutzerdefinierte Löscher oben kann durch ersetzt werden
-
der std::default_delete
partielle 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, es sei denn, Sie benötigen tatsächlich die gemeinsame Verwaltung des verwalteten Objekts, a unique_ptr
ist für diese Aufgabe besser geeignet, da es teilweise auf Array-Typen spezialisiert ist.
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 bereitgestellt Bibliotheksgrundlagen Technische Spezifikationdie vergrößert shared_ptr
damit es sofort einsatzbereit ist, wenn es ein Array von Objekten besitzt. Der aktuelle Entwurf der shared_ptr
Änderungen, die für diesen TS vorgesehen sind, finden Sie in N4082. Diese Änderungen werden über die zugänglich sein std::experimental
Namespace und enthalten in der <experimental/memory>
Header. Einige der relevanten Änderungen zur Unterstützung shared_ptr
für Arrays sind:
— Die Definition des Elementtyps element_type
Änderungen
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;
– Nicht so wie unique_ptr
partielle Spezialisierung für Arrays, beides shared_ptr<T[]>
und shared_ptr<T[N]>
gültig sein und beides ergibt sich delete[]
für das verwaltete Array von Objekten aufgerufen wird.
template<class Y> explicit shared_ptr(Y* p);
Erfordert: Y
muss ein vollständiger Typ sein. Der Ausdruck delete[] p
wann T
ist ein Array-Typ, oder delete p
wann T
ist kein Array-Typ, muss wohlgeformt sein, ein gut definiertes Verhalten haben und keine Ausnahmen auslösen. Wann T
ist U[N]
, Y(*)[N]
soll umwandelbar sein T*
; wann T
ist U[]
, Y(*)[]
soll umwandelbar sein T*
; Andernfalls, Y*
soll umwandelbar sein T*
.
Eine möglicherweise einfachere Alternative, die Sie möglicherweise verwenden können, ist shared_ptr<vector<int>>
.
FWIT, Sie können auch nur die Verwendung in Erwägung ziehen
std::vector
. Sie müssen darauf achten, das Array mithilfe von Referenzen herumzureichen, 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, wenn Sie es jemals wollen.– Nicu Stiurca
30. November 2012 um 11:57 Uhr
Wenn die Größe des Arrays zur Kompilierzeit bestimmt wird, können Sie auch die Verwendung von in Betracht ziehen
std::array
. es ist schon fast das gleiche wie ein rohes Array, aber mit der richtigen Semantik für die Verwendung in den meisten Bibliothekskomponenten. Vor allem Gegenstände dieser Art werden mit zerstörtdelete
nichtdelete[]
. Und andersvector
speichert es die Daten direkt im Objekt, sodass Sie keine zusätzliche Zuordnung erhalten.– Celtschk
19. April 2015 um 13:23 Uhr