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)
Défini dans l'en-tête <memory>
template < class T, class ... Args >
shared_ptr < T > make_shared ( Args && ... args ) ;
(1) (depuis C++11)
template < class T >
shared_ptr < T > make_shared ( std:: size_t N ) ;
(2) (depuis C++20)
template < class T >
shared_ptr < T > make_shared ( ) ;
(3) (depuis C++20)
template < class T >
shared_ptr < T > make_shared ( std:: size_t N, const std:: remove_extent_t < T > & u ) ;
(4) (depuis C++20)
template < class T >
shared_ptr < T > make_shared ( const std:: remove_extent_t < T > & u ) ;
(5) (depuis C++20)
template < class T >
shared_ptr < T > make_shared_for_overwrite ( ) ;
(6) (depuis C++20)
template < class T >
shared_ptr < T > make_shared_for_overwrite ( std:: size_t N ) ;
(7) (depuis C++20)

Alloue de la mémoire pour un objet et initialise l'objet avec les arguments fournis. Retourne un std::shared_ptr gérant l'objet nouvellement créé.

1) L'objet est de type T , et est construit comme par :: new ( pv ) T ( std:: forward < Args > ( args ) ... ) , où pv est un pointeur void * vers un espace de stockage adapté pour contenir un objet de type T . Si l'objet doit être détruit, il est détruit comme par pt - > ~T ( ) , où pt est un pointeur vers cet objet de type T .

Cette surcharge participe à la résolution de surcharge seulement si T n'est pas un type tableau.

(depuis C++20)
2) L'objet est de type std:: remove_extent_t < T > [ N ] . Chaque élément a une valeur initiale par défaut.
Cette surcharge participe à la résolution de surcharge uniquement si T est un type de tableau non borné.
3) L'objet est de type T . Chaque élément a une valeur initiale par défaut.
Cette surcharge participe à la résolution de surcharge uniquement si T est un type tableau borné.
4) L'objet est de type std:: remove_extent_t < T > [ N ] . Chaque élément possède la valeur initiale u .
Cette surcharge participe à la résolution de surcharge uniquement si T est un type de tableau non borné.
5) L'objet est de type T . Chaque élément a la valeur initiale u .
Cette surcharge participe à la résolution de surcharge uniquement si T est un type de tableau borné.
6) L'objet est de type T .
  • Si T n'est pas un type tableau, l'objet est construit comme par :: new ( pv ) T , où pv est un pointeur void * vers un espace de stockage adapté pour contenir un objet de type T . Si l'objet doit être détruit, il est détruit comme par pt - > ~T ( ) , où pt est un pointeur vers cet objet de type T .
  • Si T est un type tableau à taille fixe, la valeur initiale est non spécifiée pour chaque élément.
Cette surcharge participe à la résolution de surcharge seulement si T n'est pas un type tableau ou est un type tableau à taille fixe.
7) L'objet est de type std:: remove_extent_t < T > [ N ] . La valeur initiale n'est pas spécifiée pour chaque élément.
Cette surcharge participe à la résolution de surcharge uniquement si T est un type de tableau non borné.

Table des matières

Initialisation et destruction des éléments du tableau

Les éléments du tableau de type U sont initialisés dans l'ordre croissant de leurs adresses.

  • Si U n'est pas un type tableau, chaque élément est construit comme par l'expression suivante, où pv est un pointeur void * vers un stockage adapté pour contenir un objet de type U :
2,3) :: new ( pv ) U ( )
4,5) :: new ( pv ) U ( u )
6,7) :: new ( pv ) U
  • Sinon, initialise récursivement les éléments de chaque élément. Pour la dimension suivante :

Lorsque la durée de vie de l'objet géré par le std::shared_ptr retourné se termine, ou lorsque l'initialisation d'un élément du tableau lève une exception, les éléments initialisés sont détruits dans l'ordre inverse de leur construction initiale.

Pour chaque élément du tableau de type non-tableau U à détruire, il est détruit comme par pu - > ~U ( ) , où pu est un pointeur vers cet élément du tableau de type U .

(depuis C++20)

Paramètres

args - liste d'arguments avec lesquels un objet de T sera construit
N - taille du tableau à utiliser
u - la valeur initiale pour initialiser chaque élément du tableau

Valeur de retour

std::shared_ptr vers un objet de type T ou std:: remove_extent_t < T > [ N ] si T est un type de tableau non borné (depuis C++20) .

Pour le std::shared_ptr r retourné, r. get ( ) renvoie un pointeur non nul et r. use_count ( ) renvoie 1 .

Exceptions

Peut lever std::bad_alloc ou toute exception levée par le constructeur de T . Si une exception est levée, les fonctions n'ont aucun effet. Si une exception est levée durant la construction du tableau, les éléments déjà initialisés sont détruits dans l'ordre inverse. (depuis C++20)

Notes

Ces fonctions allouent généralement plus de mémoire que sizeof ( T ) pour permettre des structures de gestion internes telles que les compteurs de référence.

Ces fonctions peuvent être utilisées comme alternative à std:: shared_ptr < T > ( new T ( args... ) ) . Les compromis sont :

  • std:: shared_ptr < T > ( new T ( args... ) ) effectue au moins deux allocations (une pour l'objet T et une pour le bloc de contrôle du pointeur partagé), tandis que std :: make_shared < T > effectue généralement une seule allocation (la norme le recommande, mais ne l'exige pas ; toutes les implémentations connues le font).
  • Si un std::weak_ptr référence le bloc de contrôle créé par std::make_shared après la fin de la durée de vie de tous les propriétaires partagés, la mémoire occupée par T persiste jusqu'à ce que tous les propriétaires faibles soient également détruits, ce qui peut être indésirable si sizeof ( T ) est important.
  • std:: shared_ptr < T > ( new T ( args... ) ) peut appeler un constructeur non public de T s'il est exécuté dans un contexte où il est accessible, tandis que std::make_shared nécessite un accès public au constructeur sélectionné.
  • Contrairement aux constructeurs de std::shared_ptr , std::make_shared n'autorise pas de suppresseur personnalisé.
  • std::make_shared utilise :: new , donc si un comportement spécial a été configuré en utilisant un operator new spécifique à la classe, il différera de std:: shared_ptr < T > ( new T ( args... ) ) .
(jusqu'à C++20)
  • du code tel que f ( std:: shared_ptr < int > ( new int ( 42 ) ) , g ( ) ) peut provoquer une fuite de mémoire si g est appelée après new int ( 42 ) et lève une exception, tandis que f ( std :: make_shared < int > ( 42 ) , g ( ) ) est sûr, car deux appels de fonction ne sont jamais entrelacés .
(jusqu'à C++17)

Un constructeur active shared_from_this avec un pointeur ptr de type U* signifie qu'il détermine si U possède une classe de base non ambiguë et accessible (depuis C++17) qui est une spécialisation de std::enable_shared_from_this , et si c'est le cas, le constructeur évalue 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 ) ) ;
.

L'assignation à weak_this n'est pas atomique et entre en conflit avec tout accès potentiellement concurrent au même objet. Cela garantit que les appels futurs à shared_from_this() partageront la propriété avec le std::shared_ptr créé par ce constructeur de pointeur brut.

Le test ptr - > weak_this  . expired ( ) dans le code ci-dessus garantit que weak_this n'est pas réaffecté s'il indique déjà un propriétaire. Ce test est requis à partir de C++17.

Macro de test de fonctionnalité Valeur Norme Fonctionnalité
__cpp_lib_shared_ptr_arrays 201707L (C++20) Support des tableaux pour std::make_shared ; surcharges ( 2-5 )
__cpp_lib_smart_ptr_for_overwrite 202002L (C++20) Création de pointeurs intelligents avec initialisation par défaut ( std::allocate_shared_for_overwrite , std::make_shared_for_overwrite , std::make_unique_for_overwrite ); surcharges ( 6,7 )

Exemple

#include <iostream>
#include <memory>
#include <type_traits>
#include <vector>
struct C
{
    // constructeurs nécessaires (jusqu'à C++20)
    C(int i) : i(i) {}
    C(int i, float f) : i(i), f(f) {}
    int i;
    float f{};
};
int main()
{
    // utilisation de « auto » pour le type de « sp1 »
    auto sp1 = std::make_shared<C>(1); // surcharge (1)
    static_assert(std::is_same_v<decltype(sp1), std::shared_ptr<C>>);
    std::cout << "sp1->{ i:" << sp1->i << ", f:" << sp1->f << " }\n";
    // être explicite avec le type de « sp2 »
    std::shared_ptr<C> sp2 = std::make_shared<C>(2, 3.0f); // surcharge (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 vers un float[64] initialisé par valeur ; surcharge (2):
    std::shared_ptr<float[]> sp3 = std::make_shared<float[]>(64);
    // shared_ptr vers un long[5][3][4] initialisé par valeur ; surcharge (2) :
    std::shared_ptr<long[][3][4]> sp4 = std::make_shared<long[][3][4]>(5);
    // shared_ptr vers un short[128] initialisé par valeur ; surcharge (3) :
    std::shared_ptr<short[128]> sp5 = std::make_shared<short[128]>();
    // shared_ptr vers un int[7][6][5] initialisé par valeur ; surcharge (3) :
    std::shared_ptr<int[7][6][5]> sp6 = std::make_shared<int[7][6][5]>();
    // shared_ptr vers un double[256], où chaque élément est 2.0 ; surcharge (4) :
    std::shared_ptr<double[]> sp7 = std::make_shared<double[]>(256, 2.0);
    // shared_ptr vers un double[7][2], où chaque double[2]
    // element est {3.0, 4.0}; surcharge (4):
    std::shared_ptr<double[][2]> sp8 = std::make_shared<double[][2]>(7, {3.0, 4.0});
    // shared_ptr vers un vector<int>[4], où chaque vector
    // a pour contenu {5, 6}; surcharge (4) :
    std::shared_ptr<std::vector<int>[]> sp9 =
        std::make_shared<std::vector<int>[]>(4, {5, 6});
    // shared_ptr vers un float[512], où chaque élément est 1.0 ; surcharge (5) :
    std::shared_ptr<float[512]> spA = std::make_shared<float[512]>(1.0);
    // shared_ptr vers un double[6][2], où chaque élément double[2]
    // est {1.0, 2.0}; surcharge (5):
    std::shared_ptr<double[6][2]> spB = std::make_shared<double[6][2]>({1.0, 2.0});
    // shared_ptr vers un vector<int>[4], où chaque vector
    // a pour contenu {5, 6} ; surcharge (5) :
    std::shared_ptr<std::vector<int>[4]> spC =
        std::make_shared<std::vector<int>[4]>({5, 6});
}

Sortie :

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

Rapports de défauts

Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.

DR S'applique à Comportement tel que publié Comportement corrigé
LWG 4024 C++20 il n'était pas clair comment les objets construits dans
std::make_shared_for_overwrite sont détruits
clarifié

Voir aussi

construit un nouveau shared_ptr
(fonction membre publique)
crée un pointeur partagé qui gère un nouvel objet alloué à l'aide d'un allocateur
(modèle de fonction)
permet à un objet de créer un shared_ptr se référant à lui-même
(modèle de classe)
crée un pointeur unique qui gère un nouvel objet
(modèle de fonction)
fonctions d'allocation
(fonction)