Namespaces
Variants

std:: make_shared, std:: make_shared_for_overwrite

From cppreference.net
Memory management library
( exposition only* )
Allocators
Uninitialized memory algorithms
Constrained uninitialized memory algorithms
Memory resources
Uninitialized storage (until C++20)
( until C++20* )
( until C++20* )
( until C++20* )

Garbage collector support (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
Definiert in Header <memory>
template < class T, class ... Args >
shared_ptr < T > make_shared ( Args && ... args ) ;
(1) (seit C++11)
template < class T >
shared_ptr < T > make_shared ( std:: size_t N ) ;
(2) (seit C++20)
template < class T >
shared_ptr < T > make_shared ( ) ;
(3) (seit C++20)
template < class T >
shared_ptr < T > make_shared ( std:: size_t N, const std:: remove_extent_t < T > & u ) ;
(4) (seit C++20)
template < class T >
shared_ptr < T > make_shared ( const std:: remove_extent_t < T > & u ) ;
(5) (seit C++20)
template < class T >
shared_ptr < T > make_shared_for_overwrite ( ) ;
(6) (seit C++20)
template < class T >
shared_ptr < T > make_shared_for_overwrite ( std:: size_t N ) ;
(7) (seit C++20)

Reserviert Speicher für ein Objekt und initialisiert das Objekt mit den bereitgestellten 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 :: new ( pv ) T ( std:: forward < Args > ( args ) ... ) , wobei pv ein void * -Zeiger auf Speicher ist, der für ein Objekt vom Typ T geeignet ist. 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.

Diese Überladung nimmt nur dann 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 Standard-Initialwert.
Diese Überladung nimmt nur dann an der Überladungsauflösung teil, wenn T ein unbounded array type ist.
3) Das Objekt ist vom Typ T . Jedes Element hat einen Standardinitialwert.
Diese Überladung nimmt nur dann an der Überladungsauflösung teil, wenn T ein bounded array type ist.
4) Das Objekt ist vom Typ std:: remove_extent_t < T > [ N ] . Jedes Element hat den Anfangswert u .
Diese Überladung nimmt nur dann an der Überladungsauflösung teil, wenn T ein unbounded array type ist.
5) Das Objekt ist vom Typ T . Jedes Element hat den Anfangswert u .
Diese Überladung nimmt nur dann an der Überladungsauflösung teil, wenn T ein bounded array type 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 für ein Objekt vom Typ T geeignet ist. 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 Array-Typ mit fester Größe ist, ist der Anfangswert für jedes Element nicht spezifiziert.
Diese Überladung nimmt nur dann an der Überladungsauflösung teil, wenn T kein Array-Typ ist oder ein Array-Typ mit fester Größe ist.
7) Das Objekt ist vom Typ std:: remove_extent_t < T > [ N ] . Der Anfangswert ist für jedes Element nicht spezifiziert.
Diese Überladung nimmt nur dann an der Überladungsauflösung teil, wenn T ein unbounded array type ist.

Inhaltsverzeichnis

Initialisierung und Zerstörung von Array-Elementen

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

  • Wenn U kein Array-Typ ist, wird jedes Element konstruiert, als ob durch den folgenden Ausdruck, wobei pv ein void * -Zeiger auf Speicher ist, der für ein Objekt vom Typ U geeignet ist:
2,3) :: new ( pv ) U ( )
4,5) :: new ( pv ) U ( u )
6,7) :: new ( pv ) U
  • Andernfalls werden die Elemente jedes Elements rekursiv initialisiert. Für die nächste Dimension:

Wenn die Lebensdauer des durch den 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 pu - > ~U ( ) , wobei pu ein Zeiger auf dieses Array-Element vom Typ U ist.

(seit C++20)

Parameter

args - Liste der Argumente, mit denen ein Objekt von T konstruiert wird
N - zu verwendende Array-Größe
u - der Initialwert zur Initialisierung jedes Elements des Arrays

Rückgabewert

std::shared_ptr zu einem Objekt vom Typ T oder std:: remove_extent_t < T > [ N ] falls T ein unbegannter 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.

Exceptions

Kann std::bad_alloc oder jede Exception werfen, die vom Konstruktor von T geworfen wird. Wenn eine Exception geworfen wird, haben die Funktionen keine Wirkung. Wenn eine Exception während der Konstruktion des Arrays geworfen wird, werden bereits initialisierte Elemente in umgekehrter Reihenfolge zerstört. (seit C++20)

Hinweise

Diese Funktionen werden typischerweise mehr Speicher allokieren als sizeof ( T ) , um Platz für interne Verwaltungsstrukturen wie Referenzzähler zu ermöglichen.

Diese Funktionen können als Alternative zu std:: shared_ptr < T > ( new T ( args... ) ) verwendet werden. Die Kompromisse sind:

  • std:: shared_ptr < T > ( new T ( args... ) ) führt mindestens zwei Allokationen durch (eine für das Objekt T und eine für den Kontrollblock des Shared Pointers), während std :: make_shared < T > typischerweise nur eine Allokation durchführt (der Standard empfiehlt dies, verlangt es aber nicht; alle bekannten Implementierungen tun dies).
  • Wenn irgendein std::weak_ptr auf den von std::make_shared erstellten Kontrollblock verweist, nachdem die Lebensdauer aller Shared-Besitzer beendet ist, bleibt der von T belegte Speicher bestehen, bis auch alle Weak-Besitzer zerstört werden, was unerwünscht sein kann, wenn sizeof ( T ) groß ist.
  • std:: shared_ptr < T > ( new T ( args... ) ) kann einen nicht-öffentlichen Konstruktor von T aufrufen, wenn er in einem Kontext ausgeführt wird, in dem er zugänglich ist, während std::make_shared öffentlichen Zugang zum ausgewählten Konstruktor erfordert.
  • Im Gegensatz zu den std::shared_ptr Konstruktoren erlaubt std::make_shared keinen benutzerdefinierten Deleter.
  • std::make_shared verwendet :: new , daher unterscheidet es sich von std:: shared_ptr < T > ( new T ( args... ) ) , falls ein spezielles Verhalten mittels eines klassen-spezifischen operator new eingerichtet wurde.
(bis C++20)
  • Code wie f ( std:: shared_ptr < int > ( new int ( 42 ) ) , g ( ) ) kann einen Speicherverlust verursachen, falls g nach new int ( 42 ) aufgerufen wird und eine Exception wirft, während f ( std :: make_shared < int > ( 42 ) , g ( ) ) sicher ist, da zwei Funktionsaufrufe niemals verschachtelt werden .
(bis C++17)

Ein Konstruktor, der shared_from_this mit einem Zeiger ptr vom Typ U* aktiviert, bedeutet, dass er bestimmt, ob U eine eindeutige und zugängliche (seit C++17) Basisklasse besitzt, die eine Spezialisierung von std::enable_shared_from_this ist, und falls 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 Besitz mit dem std::shared_ptr teilen, der durch diesen Rohzeiger-Konstruktor erstellt wurde.

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

Feature-Test Makro Wert Std Funktion
__cpp_lib_shared_ptr_arrays 201707L (C++20) Array-Unterstützung von std::make_shared ; Überladungen ( 2-5 )
__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 )

Beispiel

#include <iostream>
#include <memory>
#include <type_traits>
#include <vector>
struct C
{
    // Konstruktoren benötigt (bis C++20)
    C(int i) : i(i) {}
    C(int i, float f) : i(i), f(f) {}
    int i;
    float f{};
};
int main()
{
    // Verwendung von "auto" für den Typ von "sp1"
    auto sp1 = std::make_shared<C>(1); // Überladung (1)
    static_assert(std::is_same_v<decltype(sp1), std::shared_ptr<C>>);
    std::cout << "sp1->{ i:" << sp1->i << ", f:" << sp1->f << " }\n";
    // explizite Angabe des Typs von "sp2"
    std::shared_ptr<C> sp2 = std::make_shared<C>(2, 3.0f); // Überladung (1)
    static_assert(std::is_same_v<decltype(sp2), std::shared_ptr<C>>);
    static_assert(std::is_same_v<decltype(sp1), decltype(sp2)>);
    std::cout << "sp2->{ i:" << sp2->i << ", f:" << sp2->f << " }\n";
    // shared_ptr zu einem wertinitialisierten float[64]; Überladung (2):
    std::shared_ptr<float[]> sp3 = std::make_shared<float[]>(64);
    // shared_ptr zu einem wertinitialisierten long[5][3][4]; Überladung (2):
    std::shared_ptr<long[][3][4]> sp4 = std::make_shared<long[][3][4]>(5);
    // shared_ptr zu einem wertinitialisierten short[128]; Überladung (3):
    std::shared_ptr<short[128]> sp5 = std::make_shared<short[128]>();
    // shared_ptr zu einem wertinitialisierten int[7][6][5]; Überladung (3):
    std::shared_ptr<int[7][6][5]> sp6 = std::make_shared<int[7][6][5]>();
    // shared_ptr zu einem double[256], wobei jedes Element 2.0 ist; Überladung (4):
    std::shared_ptr<double[]> sp7 = std::make_shared<double[]>(256, 2.0);
    // shared_ptr zu einem double[7][2], wobei jeder double[2]
    // element ist {3.0, 4.0}; Überladung (4):
    std::shared_ptr<double[][2]> sp8 = std::make_shared<double[][2]>(7, {3.0, 4.0});
    // shared_ptr zu einem vector<int>[4], wobei jeder vector
    // enthält Inhalte {5, 6}; Überladung (4):
    std::shared_ptr<std::vector<int>[]> sp9 =
        std::make_shared<std::vector<int>[]>(4, {5, 6});
    // shared_ptr zu einem float[512], wobei jedes Element 1.0 ist; Überladung (5):
    std::shared_ptr<float[512]> spA = std::make_shared<float[512]>(1.0);
    // shared_ptr zu einem double[6][2], wobei jedes double[2]-Element
    // ist {1.0, 2.0}; Überladung (5):
    std::shared_ptr<double[6][2]> spB = std::make_shared<double[6][2]>({1.0, 2.0});
    // shared_ptr zu einem vector<int>[4], wobei jeder vector
    // enthält Inhalte {5, 6}; Überladung (5):
    std::shared_ptr<std::vector<int>[4]> spC =
        std::make_shared<std::vector<int>[4]>({5, 6});
}

Ausgabe:

sp1->{ i:1, f:0 }
sp2->{ i:2, f:3 }

Fehlerberichte

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

DR Angewendet auf Verhalten wie veröffentlicht Korrektes Verhalten
LWG 4024 C++20 es war unklar, wie die in
std::make_shared_for_overwrite konstruierten Objekte zerstört werden
klargestellt

Siehe auch

konstruiert neuen shared_ptr
(öffentliche Elementfunktion)
erstellt einen Shared Pointer, der ein neues Objekt verwaltet, das mit einem Allokator alloziert wurde
(Funktionstemplate)
ermöglicht einem Objekt, einen shared_ptr zu erstellen, der auf sich selbst verweist
(Klassentemplate)
erstellt einen Unique Pointer, der ein neues Objekt verwaltet
(Funktionstemplate)
Allokierungsfunktionen
(Funktion)