Comment déclarer std :: unique_ptr et quelle en est l’utilité?

J’essaie de comprendre comment fonctionne std::unique_ptr et pour cela j’ai trouvé ce document. L’auteur part de l’exemple suivant:

 #include  //declarations of unique_ptr using std::unique_ptr; // default construction unique_ptr up; //creates an empty object // initialize with an argument unique_ptr uptr (new int(3)); double *pd= new double; unique_ptr uptr2 (pd); // overloaded * and -> *uptr2 = 23.5; unique_ptr ups (new std::ssortingng("hello")); int len=ups->size(); 

Ce qui me déroute, c’est que dans cette ligne

 unique_ptr uptr (new int(3)); 

Nous utilisons un entier comme argument (entre parenthèses) et ici

 unique_ptr uptr2 (pd); 

nous avons utilisé un pointeur comme argument. Cela fait-il une différence?

Ce qui n’est pas clair non plus pour moi, c’est comment les pointeurs, déclarés de cette manière, seront différents des pointeurs déclarés de manière “normale”.

Le constructeur de unique_ptr accepte un pointeur brut sur un object de type T (donc, il accepte un T* ).

Dans le premier exemple:

 unique_ptr uptr (new int(3)); 

Le pointeur est le résultat d’une new expression, tandis que dans le deuxième exemple:

 unique_ptr uptr2 (pd); 

Le pointeur est stocké dans la variable pd .

Conceptuellement, rien ne change (vous construisez un unique_ptr partir d’un pointeur brut), mais la seconde approche est potentiellement plus dangereuse, car elle vous permet, par exemple, de:

 unique_ptr uptr2 (pd); // ... unique_ptr uptr3 (pd); 

Ayant donc deux pointeurs uniques qui encapsulent efficacement le même object (violant ainsi la sémantique d’un pointeur unique ).

C’est pourquoi le premier formulaire pour créer un pointeur unique est meilleur, lorsque cela est possible. Notez que dans C ++ 14 nous pourrons faire:

 unique_ptr p = make_unique(42); 

Ce qui est à la fois plus clair et plus sûr. En ce qui concerne votre doute:

Ce qui n’est pas clair non plus pour moi, c’est comment les pointeurs, déclarés de cette manière, seront différents des pointeurs déclarés de manière “normale”.

Les pointeurs intelligents sont supposés modéliser la propriété de l’object et s’occuper automatiquement de détruire l’object pointu lorsque le dernier pointeur (intelligent, propriétaire) de cet object est hors de scope.

De cette façon, vous n’avez pas à vous souvenir de delete objects alloués dynamicment – le destructeur du pointeur intelligent le fera pour vous – ni à vous soucier de ne pas déréférencer un pointeur (en suspens) sur un object déjà détruit. :

 { unique_ptr p = make_unique(42); // Going out of scope... } // I did not leak my integer here! The destructor of unique_ptr called delete 

Maintenant, unique_ptr est un pointeur intelligent qui modélise la propriété unique, ce qui signifie qu’à tout moment dans votre programme, il ne doit y avoir qu’un seul pointeur (propriétaire) sur l’object pointé – c’est pourquoi unique_ptr n’est pas copiable.

Tant que vous utilisez des pointeurs intelligents d’une manière qui ne rompt pas le contrat implicite dont vous avez besoin, vous aurez la garantie qu’aucune mémoire ne sera perdue et que la politique de propriété appropriée à votre object sera appliquée. Les pointeurs bruts ne vous donnent pas cette garantie.

Les pointeurs uniques sont garantis pour être détruits lorsque vous sortez de la scope. http://fr.cppreference.com/w/cpp/memory/unique_ptr

Dans le cas:

 unique_ptr uptr2 (pd); 

pd sera détruit quand vous sortez de la scope. Cela facilite la gestion de la mémoire par suppression automatique.

puis cas de unique_ptr uptr (new int(3)); n’est pas différent sauf que le pointeur brut n’est assigné à aucune variable ici

Il n’y a pas de différence dans les deux concepts d’affectation à unique_ptr.

 int* intPtr = new int(3); unique_ptr uptr (intPtr); 

est similaire à

 unique_ptr uptr (new int(3)); 

comment les pointeurs, déclarés de cette manière, seront différents des pointeurs déclarés de manière “normale”.

Si vous créez un entier dans l’espace de tas (en utilisant un nouveau mot-clé ou un malloc ), vous devrez alors effacer vous-même cette mémoire (en utilisant respectivement delete ou free ).

Dans le code ci-dessous,

 int* heapInt = new int(5);//initialize int in heap memory . .//use heapInt . delete heapInt; 

Ici, vous devrez supprimer heapInt, une fois terminé. S’il n’est pas supprimé, une fuite de mémoire se produit.
Pour éviter de telles memory leaks, unique_ptr est utilisé, où unique_ptr supprime automatiquement l’espace occupé par heapInt lorsqu’il est hors de scope.