Namensräume
Varianten
Aktionen

std::allocate_shared, std::allocate_shared_for_overwrite

Von cppreference.com
< cpp‎ | memory‎ | shared ptr
 
 
Speicherverwaltungsbibliothek
(nur Exposition*)
Algorithmen für uninitialisierten Speicher
(C++17)
(C++17)
(C++17)
Beschränkte uninitialisierte
Speicher-Algorithmen
C-Bibliothek

Allocatoren
Speicherressourcen
Unterstützung für Garbage Collection
(C++11)(bis C++23)
(C++11)(bis C++23)
(C++11)(bis C++23)
(C++11)(bis C++23)
(C++11)(bis C++23)
(C++11)(bis C++23)
Uninitialisierter Speicher
Explizites Lebenszeitmanagement
 
 
Definiert in Header <memory>
template< class T, class Alloc, class... Args >
shared_ptr<T> allocate_shared( const Alloc& alloc, Args&&... args );
(1) (seit C++11)
template< class T, class Alloc >
shared_ptr<T> allocate_shared( const Alloc& alloc, std::size_t N );
(2) (seit C++20)
template< class T, class Alloc >
shared_ptr<T> allocate_shared( const Alloc& alloc );
(3) (seit C++20)
template< class T, class Alloc >

shared_ptr<T> allocate_shared( const Alloc& alloc, std::size_t N,

                               const std::remove_extent_t<T>& u );
(4) (seit C++20)
template< class T, class Alloc >

shared_ptr<T> allocate_shared( const Alloc& alloc,

                               const std::remove_extent_t<T>& u );
(5) (seit C++20)
template< class T, class Alloc >
shared_ptr<T> allocate_shared_for_overwrite( const Alloc& alloc );
(6) (seit C++20)
template< class T, class Alloc >

shared_ptr<T> allocate_shared_for_overwrite( const Alloc& alloc,

                                             std::size_t N );
(7) (seit C++20)

Ordnet Speicher für ein Objekt mithilfe einer Kopie von alloc (rebound für einen nicht spezifizierten value_type) und initialisiert das Objekt mit den übergebenen Argumenten. Gibt ein std::shared_ptr-Objekt zurück, das das neu erstellte Objekt verwaltet.

1) Das Objekt ist vom Typ T und wird konstruiert, als ob durch std::allocator_traits<Alloc>::construct
    (a, pt, (std::forward<Args>(args)...), wobei pt ein std::remove_cv_t<T>* Zeiger auf Speicher ist, der geeignet ist, ein Objekt vom Typ std::remove_cv_t<T> zu halten. Wenn das Objekt zerstört werden soll, wird es zerstört, als ob durch std::allocator_traits<Alloc>::destroy(a, pt), wobei pt ein Zeiger auf dieses Objekt vom Typ std::remove_cv_t<T> ist.
In der obigen Beschreibung ist a vom Typ Alloc und ist eine potenziell rebound-Kopie von alloc.

Diese Überladung nimmt nur an der Überladungsauflösung teil, wenn T kein Array-Typ ist.

(seit C++20)
2) Das Objekt ist vom Typ std::remove_extent_t<T>[N]. Jedes Element hat einen Standardinitialisierungswert.
Diese Überladung nimmt nur an der Überladungsauflösung teil, wenn T ein unbegrenzter Array-Typ ist.
3) Das Objekt ist vom Typ T. Jedes Element hat einen Standardinitialisierungswert.
Diese Überladung nimmt nur an der Überladungsauflösung teil, wenn T ein begrenzter Array-Typ ist.
4) Das Objekt ist vom Typ std::remove_extent_t<T>[N]. Jedes Element hat den Initialisierungswert u.
Diese Überladung nimmt nur an der Überladungsauflösung teil, wenn T ein unbegrenzter Array-Typ ist.
5) Das Objekt ist vom Typ T. Jedes Element hat den Initialisierungswert u.
Diese Überladung nimmt nur an der Überladungsauflösung teil, wenn T ein begrenzter Array-Typ ist.
6) Das Objekt ist vom Typ T.
  • Wenn T kein Array-Typ ist, wird das Objekt konstruiert, als ob durch ::new (pv) T, wobei pv ein void* Zeiger auf Speicher ist, der geeignet ist, ein Objekt vom Typ T zu halten. Wenn das Objekt zerstört werden soll, wird es zerstört, als ob durch pt->~T(), wobei pt ein Zeiger auf dieses Objekt vom Typ T ist.
  • Wenn T ein begrenzter Array-Typ ist, ist der Initialisierungswert für jedes Element undefiniert.
Diese Überladung nimmt nur an der Überladungsauflösung teil, wenn T kein Array-Typ ist oder ein begrenzter Array-Typ ist.
7) Das Objekt ist vom Typ std::remove_extent_t<T>[N]. Der Initialisierungswert ist für jedes Element undefiniert.
Diese Überladung nimmt nur an der Überladungsauflösung teil, wenn T ein unbegrenzter Array-Typ ist.

Inhalt

Initialisierung und Zerstörung von Array-Elementen

In der folgenden Beschreibung ist a vom Typ Alloc und ist eine potenziell rebound-Kopie von alloc.

Array-Elemente vom Typ U werden in aufsteigender Reihenfolge ihrer Adressen initialisiert.

  • Wenn U kein Array-Typ ist, wird jedes Element wie durch den folgenden Ausdruck konstruiert, wobei pu ein std::remove_cv_t<U>* Zeiger auf Speicher ist, der geeignet ist, ein Objekt vom Typ std::remove_cv_t<U> zu halten, und pv ein void* Zeiger auf Speicher ist, der geeignet ist, ein Objekt vom Typ U zu halten
2,3) std::allocator_traits<Alloc>::construct(a, pu)
4,5) std::allocator_traits<Alloc>::construct(a, pu, u)
6,7) ::new (pv) U
  • Andernfalls werden die Elemente rekursiv initialisiert. Für die nächste Dimension
  • wird U zu std::remove_extent_t<U>.
  • Für die Überladungen (4,5) wird u zum entsprechenden Element von u.

Wenn die Lebensdauer des vom zurückgegebenen std::shared_ptr verwalteten Objekts endet oder wenn die Initialisierung eines Array-Elements eine Ausnahme auslöst, werden die initialisierten Elemente in umgekehrter Reihenfolge ihrer ursprünglichen Konstruktion zerstört.

Für jedes zu zerstörende Array-Element vom Nicht-Array-Typ U wird es zerstört, als ob durch den folgenden Ausdruck

2-5) std::allocator_traits<Alloc>::destroy(a, pu), wobei pu ein U* Zeiger auf dieses Array-Element vom Typ U ist
6,7) pu->~U(), wobei pu ein Zeiger auf dieses Array-Element vom Typ U ist
(seit C++20)

[bearbeiten] Parameter

alloc - der zu verwendende Allocator
args... - Liste der Argumente, mit denen eine Instanz von T konstruiert wird
N - Array-Größe, die verwendet werden soll
u - der Initialisierungswert, mit dem jedes Element des Arrays initialisiert werden soll

[bearbeiten] Rückgabewert

std::shared_ptr auf ein Objekt vom Typ T oder std::remove_extent_t<T>[N], wenn T ein unbegrenzter Array-Typ ist(seit C++20).

Für den zurückgegebenen std::shared_ptr r gibt r.get() einen nicht-Null-Zeiger zurück und r.use_count() gibt 1 zurück.

[bearbeiten] Ausnahmen

Kann die Ausnahmen auslösen, die von Alloc::allocate() oder vom Konstruktor von T ausgelöst werden. Wenn eine Ausnahme ausgelöst wird, hat (1) keine Auswirkungen. Wenn während der Konstruktion des Arrays eine Ausnahme ausgelöst wird, werden bereits initialisierte Elemente in umgekehrter Reihenfolge zerstört(seit C++20).

[bearbeiten] Hinweise

Diese Funktionen weisen typischerweise mehr Speicher zu als sizeof(T), um interne Verwaltungsstrukturen wie Referenzzähler zu ermöglichen.

Wie std::make_shared führt diese Funktion typischerweise nur eine einzige Zuweisung durch und platziert sowohl das T-Objekt als auch den Steuerblock in dem zugewiesenen Speicherblock (der Standard empfiehlt dies, schreibt es aber nicht vor; alle bekannten Implementierungen tun dies). Eine Kopie von alloc wird als Teil des Steuerblocks gespeichert, damit sie zur Freigabe verwendet werden kann, sobald sowohl die gemeinsam genutzten als auch die schwachen Referenzzähler Null erreichen.

Im Gegensatz zu den std::shared_ptr Konstruktoren akzeptiert std::allocate_shared keinen separaten benutzerdefinierten Deleter: Der bereitgestellte Allocator wird zur Zerstörung des Steuerblocks und des T-Objekts sowie zur Freigabe ihres gemeinsamen Speicherblocks verwendet.

std::shared_ptr unterstützt Array-Typen (ab C++17), aber std::allocate_shared nicht. Diese Funktionalität wird von boost::allocate_shared unterstützt.

(bis C++20)

Ein Konstruktor, der shared_from_this aktiviert mit einem Zeiger ptr vom Typ U* bedeutet, dass er prüft, ob U eine eindeutige und zugängliche(seit C++17) Basisklasse hat, die eine Spezialisierung von std::enable_shared_from_this ist, und wenn ja, wertet der Konstruktor if (ptr != nullptr && ptr->weak_this .expired())
    ptr->weak_this = std::shared_ptr<std::remove_cv_t<U>>
        (*this, const_cast<std::remove_cv_t<U>*>(ptr)); aus.

Die Zuweisung an weak_this ist nicht atomar und steht in Konflikt mit jedem potenziell gleichzeitigen Zugriff auf dasselbe Objekt. Dies stellt sicher, dass zukünftige Aufrufe von shared_from_this() den durch diesen Rohzeiger-Konstruktor erstellten gemeinsamen Besitz mit dem std::shared_ptr teilen würden.

Der Test ptr->weak_this .expired() im obigen Code stellt sicher, dass weak_this nicht neu zugewiesen wird, wenn er bereits einen Besitzer anzeigt. Dieser Test ist ab C++17 erforderlich.

Feature-Test-Makro Wert Std Feature
__cpp_lib_smart_ptr_for_overwrite 202002L (C++20) Smart-Pointer-Erstellung mit Standardinitialisierung (std::allocate_shared_for_overwrite, std::make_shared_for_overwrite, std::make_unique_for_overwrite); Überladungen (6,7)

[bearbeiten] Beispiel

#include <cstddef>
#include <iostream>
#include <memory>
#include <memory_resource>
#include <vector>
 
class Value
{
    int i;
public:
    Value(int i) : i(i) { std::cout << "Value(), i = " << i << '\n'; }
    ~Value() { std::cout << "~Value(), i = " << i << '\n'; }
    void print() const { std::cout << "i = " << i << '\n'; }
};
 
int main()
{
    // Create a polymorphic allocator using the monotonic buffer resource
    std::byte buffer[sizeof(Value) * 8];
    std::pmr::monotonic_buffer_resource resource(buffer, sizeof(buffer));
    std::pmr::polymorphic_allocator<Value> allocator(&resource);
 
    std::vector<std::shared_ptr<Value>> v;
 
    for (int i{}; i != 4; ++i)
        // Use std::allocate_shared with the custom allocator
        v.emplace_back(std::allocate_shared<Value>(allocator, i));
 
    for (const auto& sp : v)
        sp->print();
} //< All shared pointers will automatically clean up when they go out of scope.

Ausgabe

Value(), i = 0
Value(), i = 1
Value(), i = 2
Value(), i = 3
i = 0
i = 1
i = 2
i = 3
~Value(), i = 0
~Value(), i = 1
~Value(), i = 2
~Value(), i = 3

[bearbeiten] Fehlerberichte

Die folgenden Verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.

DR angewendet auf Verhalten wie veröffentlicht Korrigiertes Verhalten
LWG 3216 C++20 std::allocate_shared rebound den
Allocator immer vor der Konstruktion und Zerstörung von Objekten
Rebinding ist optional
LWG 4024 C++20 war unklar, wie die in
std::allocate_shared_for_overwrite konstruierten Objekte zerstört werden
wurde klargestellt

[bearbeiten] Siehe auch

erstellt einen neuen shared_ptr
(public member function) [edit]
erstellt einen geteilten Zeiger, der ein neues Objekt verwaltet
(Funktionsschablone) [bearbeiten]