Namespaces
Variants

std:: unique_ptr

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 Deleter = std:: default_delete < T >

> class unique_ptr ;
(1) (depuis C++11)
template <

class T,
class Deleter

> class unique_ptr < T [ ] , Deleter > ;
(2) (depuis C++11)

std::unique_ptr est un pointeur intelligent qui possède (est responsable de) et gère un autre objet via un pointeur, et élimine ensuite cet objet lorsque le unique_ptr sort de la portée.

L'objet est éliminé, en utilisant le suppresseur associé, lorsque l'une des situations suivantes se produit :

  • l'objet unique_ptr gestionnaire est détruit.
  • l'objet unique_ptr gestionnaire se voit attribuer un autre pointeur via operator= ou reset() .

L'objet est éliminé, en utilisant un suppresseur potentiellement fourni par l'utilisateur, en appelant get_deleter ( ) ( ptr ) . Le suppresseur par défaut ( std::default_delete ) utilise l'opérateur delete , qui détruit l'objet et désalloue la mémoire.

Un unique_ptr peut également ne posséder aucun objet, auquel cas il est décrit comme vide .

Il existe deux versions de unique_ptr :

  1. Gère un seul objet (par exemple, alloué avec new ).
  2. Gère un tableau d'objets alloué dynamiquement (par exemple, alloué avec new [ ] ).

La classe satisfait aux exigences de MoveConstructible et de MoveAssignable , mais ni de CopyConstructible ni de CopyAssignable .

Si T* n'était pas un type valide (par exemple, T est un type référence), un programme qui instancie la définition de std :: unique_ptr < T, Deleter > est mal formé.

Exigences de type
-
Deleter doit être un FunctionObject ou une référence lvalue à un FunctionObject ou une référence lvalue à une fonction, pouvant être appelée avec un argument de type unique_ptr < T, Deleter > :: pointer .

Table des matières

Notes

Seul un unique_ptr non constant peut transférer la propriété de l'objet géré à un autre unique_ptr . Si la durée de vie d'un objet est gérée par un const std :: unique_ptr , elle est limitée à la portée dans laquelle le pointeur a été créé.

unique_ptr est couramment utilisé pour gérer la durée de vie des objets, notamment :

  • fournir une garantie d'exception aux classes et fonctions qui manipulent des objets à durée de vie dynamique, en assurant leur suppression à la fois lors d'une sortie normale et lors d'une sortie par exception.
  • transfert de propriété d'objets à propriétaire unique avec durée de vie dynamique vers des fonctions.
  • acquisition de la propriété d'objets à durée de vie dynamique et à propriété unique depuis des fonctions.
  • comme type d'élément dans les conteneurs compatibles avec le déplacement, tels que std::vector , qui contiennent des pointeurs vers des objets alloués dynamiquement (par exemple si un comportement polymorphe est souhaité).

unique_ptr peut être construit pour un type incomplet T , par exemple pour faciliter son utilisation comme handle dans l' idiome pImpl . Si le suppresseur par défaut est utilisé, T doit être complet au point du code où le suppresseur est invoqué, ce qui se produit dans le destructeur, l'opérateur d'affectation de déplacement, et la fonction membre reset de unique_ptr . (En revanche, std::shared_ptr ne peut pas être construit à partir d'un pointeur brut vers un type incomplet, mais peut être détruit là où T est incomplet). Notez que si T est une spécialisation de modèle de classe, l'utilisation de unique_ptr comme opérande, par exemple ! p nécessite que les paramètres de T soient complets en raison de l' ADL .

Si T est une classe dérivée d'une classe de base B , alors unique_ptr < T > est implicitement convertible en unique_ptr < B > . Le suppresseur par défaut du unique_ptr < B > résultant utilisera operator delete pour B , conduisant à un comportement indéfini sauf si le destructeur de B est virtuel . Notez que std::shared_ptr se comporte différemment : std:: shared_ptr < B > utilisera operator delete pour le type T et l'objet détenu sera correctement supprimé même si le destructeur de B n'est pas virtuel .

Contrairement à std::shared_ptr , unique_ptr peut gérer un objet via tout type de handle personnalisé satisfaisant NullablePointer . Cela permet, par exemple, de gérer des objets situés en mémoire partagée, en fournissant un Deleter qui définit typedef boost::offset_ptr pointer; ou un autre pointeur sophistiqué .

Macro de test de fonctionnalité Valeur Norme Fonctionnalité
__cpp_lib_constexpr_memory 202202L (C++23) constexpr std::unique_ptr

Types imbriqués

Type Définition
pointer std:: remove_reference < Deleter > :: type :: pointer si ce type existe, sinon T* . Doit satisfaire NullablePointer
element_type T , le type de l'objet géré par ce unique_ptr
deleter_type Deleter , l'objet fonction ou la référence lvalue vers une fonction ou un objet fonction, à appeler depuis le destructeur

Fonctions membres

construit un nouveau unique_ptr
(fonction membre publique)
détruit l'objet géré s'il est présent
(fonction membre publique)
assigne le unique_ptr
(fonction membre publique)
Modificateurs
retourne un pointeur vers l'objet géré et libère la propriété
(fonction membre publique)
remplace l'objet géré
(fonction membre publique)
échange les objets gérés
(fonction membre publique)
Observateurs
retourne un pointeur vers l'objet géré
(fonction membre publique)
retourne le suppresseur utilisé pour la destruction de l'objet géré
(fonction membre publique)
vérifie s'il existe un objet géré associé
(fonction membre publique)
Version objet unique, unique_ptr<T>
déréférence le pointeur vers l'objet géré
(fonction membre publique)
Version tableau, unique_ptr<T[]>
fournit un accès indexé au tableau géré
(fonction membre publique)

Fonctions non membres

crée un pointeur unique qui gère un nouvel objet
(modèle de fonction)
compare avec un autre unique_ptr ou avec nullptr
(modèle de fonction)
affiche la valeur du pointeur géré vers un flux de sortie
(modèle de fonction)
spécialise l'algorithme std::swap
(modèle de fonction)

Classes d'assistance

Prise en charge du hachage pour std::unique_ptr
(spécialisation de modèle de classe)

Exemple

#include <cassert>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <locale>
#include <memory>
#include <stdexcept>
// classe d'assistance pour la démonstration de polymorphisme à l'exécution ci-dessous
struct B
{
    virtual ~B() = default;
    virtual void bar() { std::cout << "B::bar\n"; }
};
struct D : B
{
    D() { std::cout << "D::D\n"; }
    ~D() { std::cout << "D::~D\n"; }
    void bar() override { std::cout << "D::bar\n"; }
};
// une fonction consommant un unique_ptr peut le prendre par valeur ou par référence rvalue
std::unique_ptr<D> pass_through(std::unique_ptr<D> p)
{
    p->bar();
    return p;
}
// fonction d'assistance pour la démonstration de suppresseur personnalisé ci-dessous
void close_file(std::FILE* fp)
{
    std::fclose(fp);
}
// Démonstration de liste chaînée basée sur unique_ptr
struct List
{
    struct Node
    {
        int data;
        std::unique_ptr<Node> next;
    };
    std::unique_ptr<Node> head;
    ~List()
    {
        // détruire les nœuds de la liste séquentiellement dans une boucle, le destructeur par défaut
        // aurait invoqué récursivement le destructeur de son « next », ce qui aurait
        // provoque un débordement de pile pour des listes suffisamment grandes.
        while (head)
        {
            auto next = std::move(head->next);
            head = std::move(next);
        }
    }
    void push(int data)
    {
        head = std::unique_ptr<Node>(new Node{data, std::move(head)});
    }
};
int main()
{
    std::cout << "1) Démonstration des sémantiques de propriété exclusive\n";
    {
        // Créer une ressource (en propriété exclusive)
        std::unique_ptr<D> p = std::make_unique<D>();
        // Transférer la propriété à « pass_through »,
        // qui à son tour transfère la propriété via la valeur de retour
        std::unique_ptr<D> q = pass_through(std::move(p));
        // « p » est maintenant dans un état 'vide' après déplacement, égal à nullptr
        assert(!p);
    }
    std::cout << "\n" "2) Démonstration du polymorphisme à l'exécution\n";
    {
        // Créer une ressource dérivée et y pointer via le type de base
        std::unique_ptr<B> p = std::make_unique<D>();
        // La répartition dynamique fonctionne comme prévu
        p->bar();
    }
    std::cout << "\n" "3) Démonstration de suppresseur personnalisé\n";
    std::ofstream("demo.txt") << 'x'; // préparer le fichier à lire
    {
        using unique_file_t = std::unique_ptr<std::FILE, decltype(&close_file)>;
        unique_file_t fp(std::fopen("demo.txt", "r"), &close_file);
        if (fp)
            std::cout << char(std::fgetc(fp.get())) << '\n';
    } // “close_file()” appelé ici (si “fp” n'est pas null)
    std::cout << "\n" "4) Démonstration de sécurité des exceptions et de suppresseur d'expression lambda personnalisé\n";
    try
    {
        std::unique_ptr<D, void(*)(D*)> p(new D, [](D* ptr)
        {
            std::cout << "destruction à partir d'un suppresseur personnalisé...\n";
            delete ptr;
        });
        throw std::runtime_error(""); // “p” fuiterait ici s'il s'agissait d'un pointeur brut
    }
    catch (const std::exception&)
    {
        std::cout << "Exception capturée\n";
    }
    std::cout << "\n" "5) Démonstration de unique_ptr sous forme de tableau\n";
    {
        std::unique_ptr<D[]> p(new D[3]);
    } // “D::~D()” est appelé 3 fois
    std::cout << "\n" "6) Démonstration de liste chaînée\n";
    {
        List wall;
        const int enough{1'000'000};
        for (int beer = 0; beer != enough; ++beer)
            wall.push(beer);
        std::cout.imbue(std::locale("en_US.UTF-8"));
        std::cout << enough << " bouteilles de bière sur le mur...\n";
    } // détruit toutes les bières
}

Sortie possible :

1) Démonstration de sémantique de propriété exclusive
D::D
D::bar
D::~D
2) Démonstration de polymorphisme à l'exécution
D::D
D::bar
D::~D
3) Démonstration de suppresseur personnalisé
x
4) Démonstration de sécurité d'exception et suppresseur par expression lambda
D::D
destruction depuis un suppresseur personnalisé...
D::~D
Exception capturée
5) Démonstration de forme tableau de unique_ptr
D::D
D::D
D::D
D::~D
D::~D
D::~D
6) Démonstration de liste chaînée
1,000,000 bouteilles de bière sur le mur...

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 Appliqué à Comportement publié Comportement correct
LWG 4144 C++11 T* n'était pas requis pour former un type valide requis

Voir aussi

(C++11)
pointeur intelligent avec sémantique de propriété partagée d'objet
(modèle de classe)
(C++11)
référence faible à un objet géré par std::shared_ptr
(modèle de classe)
(C++26)
un wrapper contenant un objet alloué dynamiquement avec sémantique de type valeur
(modèle de classe)
(C++17)
objets qui contiennent des instances de tout type CopyConstructible
(classe)