Partager via


Pointeurs intelligents (C++ moderne)

Dans la programmation C++ moderne, la bibliothèque Standard inclut des pointeurs intelligents, qui sont utilisés pour garantir que les programmes sont libres de mémoire et les fuites de ressources et sont exception-safe.

Utilisations des pointeurs intelligents

Des pointeurs intelligents sont définis dans le std espace de noms dans la <memory> fichier d'en-tête.Ils sont déterminants pour la RAII ou Ressources Acquisition est Initialialization idiome de programmation.L'objectif principal de cet idiome consiste à s'assurer que resource acquisition a lieu en même temps que l'objet est initialisé, afin que toutes les ressources de l'objet sont créés et préparées en une seule ligne de code.En pratique, le principe fondamental de RAII est d'attribuer la propriété de n'importe quelle ressource alloué par tas — par exemple, mémoire allouée dynamiquement ou poignées d'objet système — à un objet alloué par pile dont le destructeur contient le code permettant de supprimer ou de libérer la ressource et tout associé à un code de nettoyage.

Dans la plupart des cas, lorsque vous initialisez un handle brut pointeur ou une ressource pour pointer vers une ressource réelle, passer le pointeur vers un pointeur intelligent immédiatement.Dans C++ modernes, pointeurs bruts sont uniquement utilisés dans des blocs de code petites fonctions étendue, boucles ou assistance limitée où les performances sont critiques et il n'y a aucun risque de confusion concernant la possession.

L'exemple suivant compare une déclaration de pointeur brut vers une déclaration de pointeur intelligent.

void UseRawPointer()
{
    // Using a raw pointer -- not recommended.
    Song* pSong = new Song(L"Nothing on You", L"Bruno Mars"); 

    // Use pSong...

    // Don't forget to delete!
    delete pSong;   
}


void UseSmartPointer()
{
    // Declare a smart pointer on stack and pass it the raw pointer.
    unique_ptr<Song> song2(new Song(L"Nothing on You", L"Bruno Mars"));

    // Use song2...
    wstring s = song2->duration_;
    //...

} // song2 is deleted automatically here.

Comme illustré dans l'exemple, un pointeur intelligent est un modèle de classe que vous déclarez sur la pile et initialisez à l'aide d'un pointeur brut qui pointe vers un objet alloué par tas.Après l'initialisation du pointeur intelligent, il possède le pointeur brut.Cela signifie que le pointeur intelligent est responsable de la suppression de la mémoire qui spécifie le pointeur brut.Le destructeur de pointeur intelligent contienne l'appel à supprimer, et parce que le pointeur intelligent est déclaré dans la pile, son destructeur est appelé lorsque le pointeur intelligent est hors de portée, même si une exception est levée dans un endroit plus haut dans la pile.

Accéder au pointeur encapsulé en utilisant les opérateurs pointeur familier, -> et *, dont la classe de pointeur intelligent surcharge pour retourner le pointeur brut encapsulé.

L'idiome de pointeur intelligent C++ ressemble à la création d'objets dans des langages tels que c#: vous créez l'objet et puis laissez le système de prendre en charge la suppression à l'heure correcte.La différence est qu'aucun séparé garbage collector s'exécute en arrière-plan ; mémoire est gérée via le standard C++ règles de portée afin que l'environnement d'exécution est plus rapide et plus efficace.

Important

Toujours créer des pointeurs intelligents sur une ligne séparée du code, jamais dans une liste de paramètres, afin qu'une fuite de ressource subtiles n'aura pas lieu en raison de certaines règles d'allocation liste paramètre.

L'exemple suivant montre comment un unique_ptr type pointeur intelligent à partir de la bibliothèque de modèles Standard pourrait être utilisé pour encapsuler un pointeur vers un objet volumineux.


class LargeObject
{
public:
    void DoSomething(){}
};

void ProcessLargeObject(const LargeObject& lo){}
void SmartPointerDemo()
{    
    // Create the object and pass it to a smart pointer
    std::unique_ptr<LargeObject> pLarge(new LargeObject());

    //Call a method on the object
    pLarge->DoSomething();

    // Pass a reference to a method.
    ProcessLargeObject(*pLarge);

} //pLarge is deleted automatically when function block goes out of scope.

L'exemple illustre les étapes essentielles suivantes pour utiliser des pointeurs intelligents.

  1. Déclarez le pointeur intelligent comme une variable automatique (locale).(N'utilisez pas le new ou malloc expression sur le pointeur intelligent lui-même.)

  2. Dans le paramètre de type, spécifiez le type pointé vers du pointeur encapsulé.

  3. Passer un pointeur brut vers un new-objet ed dans le constructeur un pointeur intelligent.(Certaines fonctions utilitaires ou les constructeurs de pointeur intelligent cela pour vous.)

  4. Utilisez la surcharge -> et * opérateurs pour accéder à l'objet.

  5. Laissez le pointeur intelligent supprimer l'objet.

Des pointeurs intelligents sont conçus pour être aussi efficace que possible à la fois en termes de mémoire et de performances.Par exemple, le membre de données uniquement dans unique_ptr est le pointeur encapsulé.Cela signifie que unique_ptr est exactement la même taille que ce pointeur, soit quatre ou huit octets.L'accès à la pointeur encapsulé à l'aide du pointeur intelligent surchargé * et - > les opérateurs n'est pas sensiblement plus lente que d'accéder directement aux pointeurs bruts.

Des pointeurs intelligents ont leurs propres fonctions membres, lesquels sont accessibles en utilisant la notation « dot ».Par exemple, certains pointeurs intelligents STL ont une fonction de membre de réinitialisation qui libère la possession du pointeur.Ceci est utile lorsque vous souhaitez libérer de la mémoire détenue par le pointeur intelligent avant que le pointeur intelligent est hors de portée, comme illustré dans l'exemple suivant.

void SmartPointerDemo2()
{
    // Create the object and pass it to a smart pointer
    std::unique_ptr<LargeObject> pLarge(new LargeObject());

    //Call a method on the object
    pLarge->DoSomething();

    // Free the memory before we exit function block.
    pLarge.reset();

    // Do some other work...

}

Généralement, les pointeurs intelligents constituent un moyen d'accéder directement à leur pointeur brut.Pointeurs intelligents STL ont une get fonction membre à cette fin, et CComPtr a un public p membre de classe.En fournissant un accès direct au pointeur sous-jacente, vous pouvez utiliser le pointeur intelligent pour gérer la mémoire dans votre propre code et toujours passer le pointeur brut au code qui ne prend pas en charge les pointeurs intelligents.

void SmartPointerDemo4()
{
    // Create the object and pass it to a smart pointer
    std::unique_ptr<LargeObject> pLarge(new LargeObject());

    //Call a method on the object
    pLarge->DoSomething();

    // Pass raw pointer to a legacy API
    LegacyLargeObjectFunction(pLarge.get());    
}

Types de pointeurs intelligents

La section suivante résume les différents types de pointeurs intelligents qui sont disponibles dans l'environnement de programmation Windows et décrit leur utilisation.

  • Pointeurs intelligents de bibliothèque Standard C++
    Utilisez ces pointeurs intelligents comme premier choix pour encapsuler des pointeurs vers les objets C++ anciens ordinaires (POCO).

    • unique_ptr
      Permet d'exactement un seul propriétaire du pointeur sous-jacente.Utiliser en tant que choix par défaut pour POCO à moins que vous sachiez que vous avez besoin d'un shared_ptr.Peuvent être déplacés vers un nouveau propriétaire, mais pas copié ou partagés.Remplace auto_ptr, qui est désapprouvée.Comparer avec boost::scoped_ptr.unique_ptrest petite et efficace ; la taille est un pointeur et qu'il prend en charge les références rvalue rapide d'insertion et l'extraction à partir des collections STL.Fichier d'en-tête : <memory>.Pour plus d'informations, consultez Comment : Créer et utiliser des instances d'unique_ptr et unique_ptr Class.

    • shared_ptr
      Comptage de référence de pointeur intelligent.À utiliser lorsque vous souhaitez affecter un pointeur brut à plusieurs propriétaires, par exemple, lorsque vous retournez une copie d'un pointeur à partir d'un conteneur mais que vous souhaitez conserver l'original.Le pointeur brut n'est pas supprimé tant que tous les shared_ptr propriétaires passée hors de portée ou possession ont abandonné dans le cas contraire.La taille est de deux pointeurs ; une pour l'objet et un pour le bloc de contrôle partagé qui contient le décompte de références.Fichier d'en-tête : <memory>.Pour plus d'informations, consultez Comment : Créer et utiliser les instances de shared_ptr et shared_ptr Class.

    • weak_ptr
      Cas particuliers pointeur intelligent pour une utilisation en conjonction avec shared_ptr.A weak_ptr donne accès à un objet appartenant à un ou plusieurs shared_ptr d'instances, mais ne participe pas le décompte de références.À utiliser lorsque vous voulez observer un objet, mais n'en avez pas besoin pour rester en vie.Obligatoire dans certains cas pour rompre les références circulaires entre shared_ptr instances.Fichier d'en-tête : <memory>.Pour plus d'informations, consultez Comment : Créer et utiliser les instances de weak_ptr et weak_ptr Class.

  • Pointeurs intelligents pour les objets COM (programmation de Windows classique)
    Lorsque vous travaillez avec des objets COM, enveloppez les pointeurs d'interface dans un type de pointeur intelligent approprié.La bibliothèque ATL (Active Template) définit plusieurs pointeurs intelligents à des fins diverses.Vous pouvez également utiliser la _com_ptr_t type de pointeur intelligent, le compilateur utilise lorsqu'il crée des classes wrapper à partir de fichiers .tlb.Il est le meilleur choix lorsque vous ne souhaitez pas inclure les fichiers d'en-tête ATL.

  • Pointeurs intelligents ATL pour les objets POCO
    En plus de pointeurs intelligents pour les objets COM ATL définit également des pointeurs intelligents et les collections de pointeurs intelligents, pour les objets C++ anciens ordinaires.En programmation Windows classique, ces types sont des alternatives utiles aux collections STL, en particulier lorsque la portabilité de code n'est pas nécessaire ou lorsque vous ne souhaitez pas mélanger les modèles de programmation de STL et ATL.

    • CAutoPtr, classe
      Pointeur intelligent qui applique la propriété unique par transfert de propriété sur la copie.Comparable à la désapprouvée std::auto_ptr classe.

    • CHeapPtr, classe
      Pointeur intelligent pour les objets qui sont alloués à l'aide de la c malloc fonction.

    • CAutoVectorPtr, classe
      Pointeur intelligent pour les tableaux qui sont alloués à l'aide de new[].

    • CAutoPtrArray, classe
      Classe qui encapsule un tableau de CAutoPtr éléments.

    • CAutoPtrList, classe
      Classe qui encapsule les méthodes permettant de manipuler une liste de CAutoPtr nœuds.

Voir aussi

Autres ressources

Accueil vers C++ (C++ moderne)

Guide de référence du langage C++

Référence de la bibliothèque C++ standard

présentation : Gestion de la mémoire en C++