Quelle est la différence entre:
std::shared_ptr<int> p = std::shared_ptr<int>( new int );
et
std::shared_ptr<int> p = std::make_shared< int >();
?
Laquelle devrais-je préférer et pourquoi?
P. S. Je suis sûr que cela a déjà dû être répondu, mais je ne trouve pas de question similaire.
Les deux exemples sont plutôt plus verbeux que nécessaire:
std::shared_ptr<int> p(new int); // or '=shared_ptr<int>(new int)' if you insist
auto p = std::make_shared<int>(); // or 'std::shared_ptr<int> p' if you insist
Quelle est la différence?
La principale différence est que la première nécessite deux allocations de mémoire: une pour l'objet géré (new int
) et un pour le compte de référence. make_shared
devrait allouer un seul bloc de mémoire et en créer les deux.
Laquelle devrais-je préférer et pourquoi?
Vous devez généralement utiliser make_shared
car c'est plus efficace. Comme indiqué dans une autre réponse, cela évite également toute possibilité de fuite de mémoire, car vous n'avez jamais de pointeur brut vers l'objet géré.
Cependant, comme indiqué dans les commentaires, il y a un inconvénient potentiel à ce que la mémoire ne soit pas libérée lorsque l'objet est détruit, s'il existe encore des pointeurs faibles empêchant la suppression du compte partagé.
En revanche, la déclaration std::shared_ptr<T> p(new T(Args...))
effectue au moins deux allocations de mémoire, ce qui peut entraîner des frais généraux inutiles.
De plus, f(shared_ptr<int>(new int(42)), g())
peut entraîner une fuite de mémoire si g lève une exception. Ce problème n'existe pas si make_shared est utilisé.
Je recommanderais donc le make_shared
approche si possible.
Soit conscient que make_shared
vous limite à l'utilisation des fonctions d'allocation/désallocation par défaut, donc si vous voulez avoir plus de contrôle, make_shared
n'est pas une option. En d'autres termes, quelque chose comme
std::shared_ptr<uint8_t>(p, [](uint8_t *p){ /*user code */});
est impossible en utilisant make_shared
. On pourrait utiliser allocate_shared
à la place, mais seul l'allocateur peut être spécifié, pas un suppresseur. Parfois, il faut contrôler l'allocation et la suppression de la classe encapsulée.