Qu'est-ce qu'un pointeur intelligent et quand dois-je en utiliser un?

1823

Qu'est-ce qu'un pointeur intelligent et quand dois-je en utiliser un?

Alex Reynolds
la source
7
Découvrez cette question: <br> Smart Pointers: Ou qui vous possède bébé
Martin York
2
Notez que l'implémentation de std :: auto_ptr dans Visual Studio 2005 est horriblement cassée. <br> http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=98871 <br> http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=101842 Utilisez le booster ceux à la place.
Richard
25
Deux excellents articles sur le sujet: - Smart Pointers - Quoi, pourquoi, lequel? - Gourou de la semaine # 25
Lazer
1
Voici le chapitre (gratuit) d'Alexandrescu sur le détail de la création de pointeurs intelligents de différentes saveurs: informit.com/articles/article.aspx?p=31529 Dans son implémentation, il utilise des arguments de modèle comme "politiques" pour spécifier les attributs qu'il veut ( par exemple, comptage de références), tandis que la bibliothèque standard utilise des classes distinctes. Notez qu'il écrivait également avant que les références rvalue ne soient disponibles pour rendre possible quelque chose comme std :: unique_ptr.
metal
Je voudrais ajouter un point de plus à la question ci-dessus, le pointeur intelligent std :: shared_ptr n'a pas d'opérateur indice et ne prend pas en charge l'arithmétique de pontage, nous pouvons utiliser get () pour obtenir un pointeur intégré.
suresh m

Réponses:

1885

MISE À JOUR

Cette réponse est plutôt ancienne et décrit donc ce qui était «bon» à l'époque, à savoir les pointeurs intelligents fournis par la bibliothèque Boost. Depuis C ++ 11, la bibliothèque standard a fourni suffisamment de types de pointeurs intelligents, et vous devriez donc privilégier l'utilisation de std::unique_ptr, std::shared_ptret std::weak_ptr.

Il y en avait aussi std::auto_ptr. Il ressemblait beaucoup à un pointeur de portée, sauf qu'il avait également la capacité dangereuse «spéciale» à copier - qui transfère également de manière inattendue la propriété.
Il était obsolète en C ++ 11 et supprimé en C ++ 17 , vous ne devriez donc pas l'utiliser.

std::auto_ptr<MyObject> p1 (new MyObject());
std::auto_ptr<MyObject> p2 = p1; // Copy and transfer ownership. 
                                 // p1 gets set to empty!
p2->DoSomething(); // Works.
p1->DoSomething(); // Oh oh. Hopefully raises some NULL pointer exception.

RÉPONSE ANCIENNE

Un pointeur intelligent est une classe qui encapsule un pointeur C ++ «brut» (ou «nu»), pour gérer la durée de vie de l'objet pointé. Il n'y a pas de type de pointeur intelligent unique, mais tous essaient d'abstraire un pointeur brut de manière pratique.

Les pointeurs intelligents devraient être préférés aux pointeurs bruts. Si vous pensez que vous devez utiliser des pointeurs (pensez d'abord si vous le faites vraiment ), vous voudrez normalement utiliser un pointeur intelligent car cela peut atténuer de nombreux problèmes avec les pointeurs bruts, oubliant principalement de supprimer l'objet et les fuites de mémoire.

Avec des pointeurs bruts, le programmeur doit détruire explicitement l'objet lorsqu'il n'est plus utile.

// Need to create the object to achieve some goal
MyObject* ptr = new MyObject(); 
ptr->DoSomething(); // Use the object in some way
delete ptr; // Destroy the object. Done with it.
// Wait, what if DoSomething() raises an exception...?

Un pointeur intelligent par comparaison définit une politique quant au moment où l'objet est détruit. Vous devez toujours créer l'objet, mais vous n'avez plus à vous soucier de le détruire.

SomeSmartPtr<MyObject> ptr(new MyObject());
ptr->DoSomething(); // Use the object in some way.

// Destruction of the object happens, depending 
// on the policy the smart pointer class uses.

// Destruction would happen even if DoSomething() 
// raises an exception

La stratégie la plus simple utilisée implique la portée de l'objet wrapper de pointeur intelligent, tel qu'implémenté par boost::scoped_ptrou std::unique_ptr.

void f()
{
    {
       std::unique_ptr<MyObject> ptr(new MyObject());
       ptr->DoSomethingUseful();
    } // ptr goes out of scope -- 
      // the MyObject is automatically destroyed.

    // ptr->Oops(); // Compile error: "ptr" not defined
                    // since it is no longer in scope.
}

Notez que les std::unique_ptrinstances ne peuvent pas être copiées. Cela empêche le pointeur d'être supprimé plusieurs fois (incorrectement). Vous pouvez cependant lui transmettre des références à d'autres fonctions que vous appelez.

std::unique_ptrs sont utiles lorsque vous souhaitez lier la durée de vie de l'objet à un bloc de code particulier, ou si vous l'avez incorporé en tant que données de membre dans un autre objet, la durée de vie de cet autre objet. L'objet existe jusqu'à ce que le bloc contenant du code soit quitté ou jusqu'à ce que l'objet contenant soit lui-même détruit.

Une stratégie de pointeur intelligent plus complexe implique le comptage des références du pointeur. Cela permet de copier le pointeur. Lorsque la dernière "référence" à l'objet est détruite, l'objet est supprimé. Cette politique est mise en œuvre par boost::shared_ptret std::shared_ptr.

void f()
{
    typedef std::shared_ptr<MyObject> MyObjectPtr; // nice short alias
    MyObjectPtr p1; // Empty

    {
        MyObjectPtr p2(new MyObject());
        // There is now one "reference" to the created object
        p1 = p2; // Copy the pointer.
        // There are now two references to the object.
    } // p2 is destroyed, leaving one reference to the object.
} // p1 is destroyed, leaving a reference count of zero. 
  // The object is deleted.

Les pointeurs comptés par référence sont très utiles lorsque la durée de vie de votre objet est beaucoup plus compliquée et n'est pas directement liée à une section particulière de code ou à un autre objet.

Il y a un inconvénient à référencer les pointeurs comptés - la possibilité de créer une référence pendante:

// Create the smart pointer on the heap
MyObjectPtr* pp = new MyObjectPtr(new MyObject())
// Hmm, we forgot to destroy the smart pointer,
// because of that, the object is never destroyed!

Une autre possibilité consiste à créer des références circulaires:

struct Owner {
   std::shared_ptr<Owner> other;
};

std::shared_ptr<Owner> p1 (new Owner());
std::shared_ptr<Owner> p2 (new Owner());
p1->other = p2; // p1 references p2
p2->other = p1; // p2 references p1

// Oops, the reference count of of p1 and p2 never goes to zero!
// The objects are never destroyed!

Pour contourner ce problème, Boost et C ++ 11 ont défini a weak_ptrpour définir une référence faible (non comptée) à a shared_ptr.

Lloyd
la source
7
Voulez-vous dire std::auto_ptr<MyObject> p1 (new MyObject());au lieu de std::auto_ptr<MyObject> p1 (new Owner());?
Mateen Ulhaq
35
Réponse géniale. Ce serait bien s'il était mis à jour pour c ++ 11. J'ai trouvé cette réponse à la recherche d'informations sur la nouvelle norme 11 et ce serait bien si les futurs visiteurs pouvaient trouver les informations mises à jour. Je sais que auto_ptr est obsolète. Je crois que shated_ptr et faiblesse_ptr existent comme décrit, et je pense que scoped_ptr est maintenant unique_ptr dans la norme. Si cela est vrai, cette réponse peut-elle être mise à jour s'il vous plaît?
SaulBack
16
Dire que la possibilité de créer une référence pendante est un inconvénient pour les pointeurs comptés par référence est absolument insensé. Les références pendantes possibles sont un inconvénient de tout pointeur C ++ . En fait, c'est exactement cet inconvénient que les pointeurs intelligents sont censés atténuer .
Michael Dorst
16
Si vous déclarez un pointeur sur un pointeur intelligent (comme cela a été fait dans l'exemple), vous abandonnez sciemment tous les avantages du pointeur intelligent. Ce n'est pas un inconvénient ou un défaut de conception, c'est l'utilisation la plus idiote imaginable.
Michael Dorst
3
A const std::auto_ptrest sûr à utiliser, si vous êtes coincé avec C ++ 03. Je l'ai beaucoup utilisé pour le modèle pimpl jusqu'à ce que j'aie accès à C ++ 11.
Toby Speight
303

Voici une réponse simple pour ces jours de C ++ moderne (C ++ 11 et versions ultérieures):

  • Qu'est-ce qu'un pointeur intelligent?
    C'est un type dont les valeurs peuvent être utilisées comme des pointeurs, mais qui offre la fonctionnalité supplémentaire de gestion automatique de la mémoire: lorsqu'un pointeur intelligent n'est plus utilisé, la mémoire vers laquelle il pointe est désallouée (voir également la définition plus détaillée sur Wikipédia ).
  • Quand devrais-je en utiliser un?
    Dans le code qui implique le suivi de la propriété d'un morceau de mémoire, l'allocation ou la désallocation; le pointeur intelligent vous évite souvent de devoir faire ces choses explicitement.
  • Mais quel pointeur intelligent dois-je utiliser dans lequel de ces cas?
    • À utiliser std::unique_ptrlorsque vous n'avez pas l'intention de contenir plusieurs références au même objet. Par exemple, utilisez-le pour un pointeur sur la mémoire qui est alloué à l'entrée dans une étendue et désalloué à la sortie de l'étendue.
    • À utiliser std::shared_ptrlorsque vous souhaitez faire référence à votre objet à partir de plusieurs emplacements - et ne souhaitez pas que votre objet soit désalloué jusqu'à ce que toutes ces références soient elles-mêmes disparues.
    • À utiliser std::weak_ptrlorsque vous souhaitez faire référence à votre objet à partir de plusieurs endroits - pour les références pour lesquelles il est acceptable d'ignorer et de désallouer (de sorte qu'ils notent simplement que l'objet a disparu lorsque vous essayez de déréférencer).
    • N'utilisez pas les boost::pointeurs intelligents ou std::auto_ptrsauf dans des cas spéciaux sur lesquels vous pouvez lire si vous le devez.
  • Hé, je n'ai pas demandé lequel utiliser!
    Ah, mais tu le voulais vraiment, admets-le.
  • Alors, quand dois-je utiliser des pointeurs réguliers?
    Surtout dans un code qui ignore la propriété de la mémoire. Ce serait généralement dans les fonctions qui obtiennent un pointeur ailleurs et qui n'allouent ni ne désallouent, et ne stockent pas une copie du pointeur qui survit à leur exécution.
einpoklum
la source
5
Il convient de noter que, bien que les pointeurs intelligents (propriétaires) aident à la bonne gestion de la mémoire, les pointeurs bruts (non propriétaires) sont toujours utiles à d'autres fins organisationnelles dans les structures de données. Herb Sutter a fait une excellente présentation sur ce sujet lors de CppCon 2016, que vous pouvez voir sur YouTube: Leak-Freedom en C ++ ... Par défaut.
wiktor.wandachowicz
1
@ wiktor.wandachowicz T*est à std::unique_ptr<T>ce qui std::weak_ptr<T>eststd::shared_ptr<T>
Caleth
@Caleth: Non, je ne dirais pas ça.
einpoklum
1
@TonyTannous: Avec respect - C'était une modification majeure; et je ne sens pas que ma réponse, qui est abstraite, en ait besoin. Je vous suggère de faire de l'exemple une réponse distincte, sur le lien vers celui-ci dans un commentaire.
einpoklum
112

Le pointeur intelligent est un type de pointeur avec des fonctionnalités supplémentaires, par exemple la désallocation automatique de la mémoire, le comptage des références, etc.

Une petite introduction est disponible sur la page Smart Pointers - Quoi, pourquoi, lequel? .

L'un des types de pointeurs intelligents simples est std::auto_ptr(chapitre 20.4.5 de la norme C ++), qui permet de désallouer automatiquement la mémoire lorsqu'elle est hors de portée et qui est plus robuste que l'utilisation d'un pointeur simple lorsque des exceptions sont levées, bien que moins flexible.

Un autre type pratique consiste à boost::shared_ptrimplémenter le comptage des références et à désallouer automatiquement la mémoire lorsqu'il ne reste aucune référence à l'objet. Cela permet d'éviter les fuites de mémoire et est facile à utiliser pour implémenter RAII .

Le sujet est traité en profondeur dans le livre "C ++ Templates: The Complete Guide" de David Vandevoorde, Nicolai M. Josuttis , chapitre Chapter 20. Smart Pointers. Quelques sujets abordés:

sergtk
la source
2
L'avertissement std::auto_ptrest déconseillé et décourage fortement car vous pouvez accidentellement transférer la propriété. - C ++ 11 supprime le besoin de Boost, utilisez: std::unique_ptr, std::shared_ptretstd::weak_ptr
ninMonkey
42

Les définitions fournies par Chris, Sergdev et Llyod sont correctes. Je préfère une définition plus simple, juste pour garder ma vie simple: un pointeur intelligent est simplement une classe qui surcharge les opérateurs -> et *. Ce qui signifie que votre objet ressemble sémantiquement à un pointeur mais vous pouvez le faire faire des choses bien plus cool, y compris le comptage de références, la destruction automatique, etc. shared_ptret auto_ptrsont suffisantes dans la plupart des cas, mais viennent avec leur propre ensemble de petites idiosyncrasies.

Sridhar Iyer
la source
30

Un pointeur intelligent est comme un pointeur normal (tapé), comme "char *", sauf lorsque le pointeur lui-même est hors de portée, ce à quoi il pointe est également supprimé. Vous pouvez l'utiliser comme vous le feriez avec un pointeur normal, en utilisant "->", mais pas si vous avez besoin d'un pointeur réel vers les données. Pour cela, vous pouvez utiliser "& * ptr".

Il est utile pour:

  • Objets qui doivent être alloués avec new, mais que vous souhaitez avoir la même durée de vie que quelque chose sur cette pile. Si l'objet est affecté à un pointeur intelligent, ils seront supprimés lorsque le programme quittera cette fonction / bloc.

  • Membres de données des classes, de sorte que lorsque l'objet est supprimé, toutes les données détenues sont également supprimées, sans code spécial dans le destructeur (vous devrez vous assurer que le destructeur est virtuel, ce qui est presque toujours une bonne chose à faire) .

Vous ne voudrez peut-être pas utiliser un pointeur intelligent lorsque:

  • ... le pointeur ne doit pas réellement posséder les données ... c.-à-d. lorsque vous utilisez simplement les données, mais que vous voulez qu'elles survivent à la fonction où vous les référencez.
  • ... le pointeur intelligent ne sera pas lui-même détruit à un moment donné. Vous ne voulez pas qu'il reste dans la mémoire qui n'est jamais détruite (comme dans un objet qui est alloué dynamiquement mais qui ne sera pas explicitement supprimé).
  • ... deux pointeurs intelligents peuvent pointer vers les mêmes données. (Il existe cependant des pointeurs encore plus intelligents qui géreront cela ... c'est ce qu'on appelle le comptage de références .)

Voir également:

marchés
la source
18

La plupart des types de pointeurs intelligents gèrent l'élimination de l'objet pointeur vers vous. C'est très pratique car vous n'avez plus à penser à éliminer manuellement les objets.

Les pointeurs intelligents les plus couramment utilisés sont std::tr1::shared_ptr(ou boost::shared_ptr), et, moins fréquemment, std::auto_ptr. Je recommande l'utilisation régulière de shared_ptr.

shared_ptrest très polyvalent et traite une grande variété de scénarios d'élimination, y compris les cas où les objets doivent être «passés à travers les limites des DLL» (le cas de cauchemar courant si des libcs différents sont utilisés entre votre code et les DLL).

Chris Jester-Young
la source
18

Un pointeur intelligent est un objet qui agit comme un pointeur, mais fournit en outre un contrôle sur la construction, la destruction, la copie, le déplacement et le déréférencement.

On peut implémenter son propre pointeur intelligent, mais de nombreuses bibliothèques fournissent également des implémentations de pointeur intelligent chacune avec des avantages et des inconvénients différents.

Par exemple, Boost fournit les implémentations de pointeur intelligent suivantes:

  • shared_ptr<T>est un pointeur vers l' Tutilisation d'un nombre de références pour déterminer quand l'objet n'est plus nécessaire.
  • scoped_ptr<T>est un pointeur supprimé automatiquement lorsqu'il sort du champ d'application. Aucune affectation n'est possible.
  • intrusive_ptr<T>est un autre pointeur de comptage de référence. Il offre de meilleures performances que shared_ptr, mais nécessite que le type Tfournisse son propre mécanisme de comptage de référence.
  • weak_ptr<T>est un pointeur faible, travaillant en conjonction avec shared_ptrpour éviter les références circulaires.
  • shared_array<T>est comme shared_ptr, mais pour les tableaux de T.
  • scoped_array<T>est comme scoped_ptr, mais pour les tableaux de T.

Ce ne sont que des descriptions linéaires de chacune et peuvent être utilisées selon les besoins, pour plus de détails et d'exemples, vous pouvez consulter la documentation de Boost.

De plus, la bibliothèque standard C ++ fournit trois pointeurs intelligents; std::unique_ptrpour une propriété unique, std::shared_ptrpour une propriété partagée et std::weak_ptr. std::auto_ptrexistait en C ++ 03 mais est désormais obsolète.

Saqlain
la source
Veuillez expliquer pourquoi scoped_ptrn'est pas comme une déclaration locale const unique_ptr- qui est également supprimée à la sortie de la portée.
einpoklum
11

Voici le lien pour des réponses similaires: http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html

Un pointeur intelligent est un objet qui agit, ressemble et se sent comme un pointeur normal mais offre plus de fonctionnalités. En C ++, les pointeurs intelligents sont implémentés en tant que classes de modèle qui encapsulent un pointeur et remplacent les opérateurs de pointeur standard. Ils ont un certain nombre d'avantages par rapport aux pointeurs classiques. Ils sont garantis pour être initialisés en tant que pointeurs null ou pointeurs vers un objet tas. L'indirection via un pointeur nul est vérifiée. Aucune suppression n'est jamais nécessaire. Les objets sont automatiquement libérés lorsque le dernier pointeur sur eux est parti. Un problème important avec ces pointeurs intelligents est que, contrairement aux pointeurs réguliers, ils ne respectent pas l'héritage. Les pointeurs intelligents ne sont pas attrayants pour le code polymorphe. Ci-dessous est un exemple pour la mise en œuvre de pointeurs intelligents.

Exemple:

template <class X>
class smart_pointer
{
          public:
               smart_pointer();                          // makes a null pointer
               smart_pointer(const X& x)            // makes pointer to copy of x

               X& operator *( );
               const X& operator*( ) const;
               X* operator->() const;

               smart_pointer(const smart_pointer <X> &);
               const smart_pointer <X> & operator =(const smart_pointer<X>&);
               ~smart_pointer();
          private:
               //...
};

Cette classe implémente un pointeur intelligent vers un objet de type X. L'objet lui-même se trouve sur le tas. Voici comment l'utiliser:

smart_pointer <employee> p= employee("Harris",1333);

Comme les autres opérateurs surchargés, p se comportera comme un pointeur normal,

cout<<*p;
p->raise_salary(0.5);
Santosh
la source
9

http://en.wikipedia.org/wiki/Smart_pointer

En informatique, un pointeur intelligent est un type de données abstrait qui simule un pointeur tout en fournissant des fonctionnalités supplémentaires, telles que la collecte automatique des déchets ou la vérification des limites. Ces fonctionnalités supplémentaires sont destinées à réduire les bogues causés par l'utilisation abusive des pointeurs tout en conservant leur efficacité. Les pointeurs intelligents gardent généralement la trace des objets qui les pointent à des fins de gestion de la mémoire. L'utilisation abusive des pointeurs est une source majeure de bogues: l'allocation constante, la désallocation et le référencement qui doivent être effectués par un programme écrit à l'aide de pointeurs, il est très probable que des fuites de mémoire se produisent. Les pointeurs intelligents tentent d'empêcher les fuites de mémoire en rendant la désallocation des ressources automatique: lorsque le pointeur vers un objet (ou le dernier d'une série de pointeurs) est détruit,

Jorge Ferreira
la source
6

Soit T une classe dans ce tutoriel Les pointeurs en C ++ peuvent être divisés en 3 types:

1) Pointeurs bruts :

T a;  
T * _ptr = &a; 

Ils détiennent une adresse mémoire à un emplacement en mémoire. À utiliser avec prudence, car les programmes deviennent complexes et difficiles à suivre.

Pointeurs avec des données const ou une adresse {Lire à l'envers}

T a ; 
const T * ptr1 = &a ; 
T const * ptr1 = &a ;

Pointeur vers un type de données T qui est une const. Cela signifie que vous ne pouvez pas modifier le type de données à l'aide du pointeur. ie *ptr1 = 19; ne fonctionnera pas. Mais vous pouvez déplacer le pointeur. ie ptr1++ , ptr1--; etc fonctionnera. Lire à l'envers: pointeur vers le type T qui est const

  T * const ptr2 ;

Un pointeur const vers un type de données T. Cela signifie que vous ne pouvez pas déplacer le pointeur mais vous pouvez modifier la valeur pointée par le pointeur. c.-à *ptr2 = 19-d. fonctionnera mais ptr2++ ; ptr2--etc. ne fonctionnera pas. Lire en arrière: pointeur const vers un type T

const T * const ptr3 ; 

Un pointeur const vers un type de données const T. Cela signifie que vous ne pouvez pas non plus déplacer le pointeur ni changer le pointeur du type de données pour qu'il soit le pointeur. c'est à dire . ptr3-- ; ptr3++ ; *ptr3 = 19;ne fonctionnera pas

3) Pointeurs intelligents : { #include <memory>}

Pointeur partagé :

  T a ; 
     //shared_ptr<T> shptr(new T) ; not recommended but works 
     shared_ptr<T> shptr = make_shared<T>(); // faster + exception safe

     std::cout << shptr.use_count() ; // 1 //  gives the number of " 
things " pointing to it. 
     T * temp = shptr.get(); // gives a pointer to object

     // shared_pointer used like a regular pointer to call member functions
      shptr->memFn();
     (*shptr).memFn(); 

    //
     shptr.reset() ; // frees the object pointed to be the ptr 
     shptr = nullptr ; // frees the object 
     shptr = make_shared<T>() ; // frees the original object and points to new object

Implémenté à l'aide du comptage de références pour garder une trace du nombre de «choses» pointant vers l'objet pointé par le pointeur. Lorsque ce nombre passe à 0, l'objet est automatiquement supprimé, c'est-à-dire que objected est supprimé lorsque tous les share_ptr pointant vers l'objet sont hors de portée. Cela élimine le casse-tête d'avoir à supprimer des objets que vous avez alloués en utilisant new.

Pointeur faible: aide à gérer la référence cyclique qui survient lors de l'utilisation du pointeur partagé.Si vous avez deux objets pointés par deux pointeurs partagés et qu'il y a un pointeur partagé interne pointant l'un vers l'autre, il y aura une référence cyclique et l'objet ne sera pas être supprimé lorsque les pointeurs partagés sortent du domaine. Pour résoudre ce problème, changez le membre interne de shared_ptr en faiblesse_ptr. Remarque: Pour accéder à l'élément pointé par un pointeur faible, utilisez lock (), cela renvoie un faible_ptr.

T a ; 
shared_ptr<T> shr = make_shared<T>() ; 
weak_ptr<T> wk = shr ; // initialize a weak_ptr from a shared_ptr 
wk.lock()->memFn() ; // use lock to get a shared_ptr 
//   ^^^ Can lead to exception if the shared ptr has gone out of scope
if(!wk.expired()) wk.lock()->memFn() ;
// Check if shared ptr has gone out of scope before access

Voir: Quand std :: faible_ptr est-il utile?

Pointeur unique: pointeur intelligent léger avec propriété exclusive. À utiliser lorsque le pointeur pointe sur des objets uniques sans partager les objets entre les pointeurs.

unique_ptr<T> uptr(new T);
uptr->memFn(); 

//T * ptr = uptr.release(); // uptr becomes null and object is pointed to by ptr
uptr.reset() ; // deletes the object pointed to by uptr 

Pour changer l'objet pointé par le ptr unique, utilisez la sémantique de déplacement

unique_ptr<T> uptr1(new T);
unique_ptr<T> uptr2(new T);
uptr2 = std::move(uptr1); 
// object pointed by uptr2 is deleted and 
// object pointed by uptr1 is pointed to by uptr2
// uptr1 becomes null 

Références: Ils peuvent essentiellement être considérés comme des pointeurs const, c'est-à-dire un pointeur qui est const et ne peut pas être déplacé avec une meilleure syntaxe.

Voir: Quelles sont les différences entre une variable pointeur et une variable de référence en C ++?

r-value reference : reference to a temporary object   
l-value reference : reference to an object whose address can be obtained
const reference : reference to a data type which is const and cannot be modified 

Référence: https://www.youtube.com/channel/UCEOGtxYTB6vo6MQ-WQ9W_nQ Merci à Andre d'avoir signalé cette question.

nnrales
la source
3

Un pointeur intelligent est une classe, un wrapper d'un pointeur normal. Contrairement aux pointeurs normaux, le cercle de vie du point intelligent est basé sur un compte de référence (combien de fois l'objet pointeur intelligent est affecté). Ainsi, chaque fois qu'un pointeur intelligent est affecté à un autre, le nombre de références internes plus plus. Et chaque fois que l'objet sort de la portée, le nombre de références moins moins.

Le pointeur automatique, bien que similaire, est totalement différent du pointeur intelligent. Il s'agit d'une classe pratique qui désalloue la ressource chaque fois qu'un objet pointeur automatique sort de la portée variable. Dans une certaine mesure, il fait fonctionner un pointeur (vers la mémoire allouée dynamiquement) comme une variable de pile (allouée statiquement au moment de la compilation).

Trombe
la source
2

Les pointeurs intelligents sont ceux où vous n'avez pas à vous soucier de la désallocation de mémoire, du partage et du transfert de ressources.

Vous pouvez très bien utiliser ces pointeurs de la même manière que n'importe quelle allocation fonctionne en Java. En java Garbage Collector fait l'affaire, tandis que dans Smart Pointers, l'astuce est effectuée par les destructeurs.

Daksh
la source
1

Les réponses existantes sont bonnes mais ne couvrent pas ce qu'il faut faire lorsqu'un pointeur intelligent n'est pas la réponse (complète) au problème que vous essayez de résoudre.

Entre autres choses (bien expliqué dans d'autres réponses), l'utilisation d'un pointeur intelligent est une solution possible à Comment utiliser une classe abstraite comme type de retour de fonction? qui a été marqué comme un double de cette question. Cependant, la première question à se poser si vous êtes tenté de spécifier une classe de base abstraite (ou en fait n'importe quelle) comme type de retour en C ++ est "que voulez-vous vraiment dire?". Il y a une bonne discussion (avec d'autres références) de la programmation orientée objet idiomatique en C ++ (et comment cela est différent des autres langages) dans la documentation de la bibliothèque de conteneurs de pointeur de boost. En résumé, en C ++, vous devez penser à la propriété. Quels pointeurs intelligents vous aident, mais ne sont pas la seule solution, ou toujours une solution complète (ils ne vous donnent pas de copie polymorphe) et ne sont pas toujours une solution que vous souhaitez exposer dans votre interface (et un retour de fonction semble terrible) un peu comme une interface). Il peut être suffisant de renvoyer une référence, par exemple. Mais dans tous ces cas (pointeur intelligent, conteneur de pointeur ou simplement retour d'une référence), vous avez changé le retour d'une valeur en une forme de référence . Si vous avez vraiment besoin d'une copie, vous devrez peut-être ajouter un "idiome" passe-partout ou aller au-delà de la POO idiomatique (ou autre) en C ++ vers un polymorphisme plus générique en utilisant des bibliothèques comme Adobe Poly ou Boost.TypeErasure.

da77a
la source