Quels sont les avantages d'utiliser std::make_unique
par rapport à l'opérateur new
pour initialiser un std::unique_ptr
?
En d'autres termes, pourquoi
std::unique_ptr<SomeObject> a = std::make_unique(SomeObject(...))
mieux que de faire
std::unique_ptr<SomeObject> a = new SomeObject(...)
J'ai essayé beaucoup de recherches en ligne et je sais qu'il est judicieux d'éviter l'opérateur new
en C++ moderne, mais je ne suis pas sûr des avantages de ce scénario précis. Empêche-t-il tout type de fuite de mémoire qui pourrait arriver? Est-il plus rapide de faire un std::make_unique
que d'utiliser new
?
make_unique
enseigne aux utilisateurs "ne dites jamais new
/delete
et new[]
/delete[]
" sans avertissements.
make_unique
partage deux avantages avec make_shared
(à l'exclusion du troisième avantage, efficacité accrue). Tout d'abord, unique_ptr<LongTypeName> up(new LongTypeName(args))
doit mentionner LongTypeName
deux fois, tandis que auto up = make_unique<LongTypeName>(args)
le mentionne une fois.
make_unique
empêche la fuite non spécifiée d'ordre d'évaluation déclenchée par des expressions telles que foo(unique_ptr<X>(new X)
, unique_ptr<Y>(new Y))
. (Suivre le conseil "ne jamais dire new
" est plus simple que "ne jamais dire new
, à moins que vous ne le donniez immédiatement à un unique_ptr
".)
make_unique
est soigneusement implémenté pour la sécurité des exceptions et il est recommandé d'appeler directement les constructeurs unique_ptr
.
make_unique
make_unique
si vous avez besoin d'un suppresseur personnalisé ou si vous utilisez un pointeur brut venant d'ailleurs.La différence est que std::make_unique
renvoie un objet de type std::unique_ptr
et new
renvoie un pointeur sur l'objet créé. Pour les échecs d'allocation de mémoire, ils lanceront tous les deux. Attends, ce n'est pas si simple. Lire plus loin.
Considérons une telle fonction ci-dessous:
_void func(ClassA* a, ClassB* b){
......
}
_
Lorsque vous passez un appel comme func(new A(), new B())
; Le compilateur peut choisir d’évaluer les arguments de la fonction de gauche à droite ou dans l’ordre de son choix. Supposons une évaluation de gauche à droite: que se passe-t-il lorsque la première expression new
réussit mais que la seconde expression new
lève?
Le véritable danger ici est lorsque vous attrapez une telle exception; Oui, vous avez peut-être intercepté l'exception levée par new B()
et repris l'exécution normale, mais new A()
a déjà réussi et sa mémoire sera silencieusement filtrée. Personne pour le nettoyer ... * sanglots ...
Mais avec _make_unique
_, vous ne pouvez pas avoir une fuite, car la pile se déroulera (et le destructeur de l'objet créé précédemment sera exécuté). Par conséquent, avoir une préférence pour _make_unique
_ vous contraindra vers exception . Dans ce cas, _std::make_unique
_ indique "Sécurité d'exception de base" que la mémoire allouée et l'objet créé par new
ne seront jamais orphelins, peu importe le type de mémoire. . Même jusqu'à la fin des temps ... :-)
Vous devriez lire Herb Sutter GoTW102