La différence est que, std::make_shared
effectue un tas de répartition, alors que l'appel de la std::shared_ptr
constructeur effectue deux.
Où faire le tas allocations de se produire?
std::shared_ptr
gère deux entités,
- le bloc de contrôle (magasins de méta-données telles que la ref-nombre, type effacé deleter, etc)
- l'objet géré
std::make_shared
effectue un seul tas d'allocation de la comptabilité de l'espace nécessaire pour le bloc de contrôle et de données. Dans les autres cas, new Obj("foo")
invoque un tas d'allocation pour la gestion de données et l' std::shared_ptr
constructeur effectue une autre pour le bloc de contrôle.
Pour de plus amples informations, consultez les notes de mise en œuvre à cppreference.
I Mise À Jour: Exception-Sécurité
Depuis l'OP semble être vous demandez-vous à propos de l'exception de sécurité côté des choses, j'ai mis à jour ma réponse.
Considérons cet exemple,
void F(const std::shared_ptr<Lhs> &lhs, const std::shared_ptr<Rhs> &rhs) { /* ... */ }
F(std::shared_ptr<Lhs>(new Lhs("foo")),
std::shared_ptr<Rhs>(new Rhs("bar")));
Parce que le C++ permet d'ordre arbitraire de l'évaluation interne, les expressions, il est possible de la commande est:
new Lhs("foo"))
new Rhs("bar"))
std::shared_ptr<Lhs>
std::shared_ptr<Rhs>
Maintenant, supposons que nous avons une exception levée lors de l'étape 2 (eg. de mémoire d'exception, Rhs
constructeur jeté quelques exception). Nous avons perdu la mémoire allouée à l'étape 1, puisque rien n'aura eu la chance de le nettoyer. Le cœur du problème, c'est que le pointeur brut avais pas passé à l' std::shared_ptr
constructeur immédiatement.
Une façon de résoudre ce problème est de les faire sur des lignes séparées, de sorte que cet arbitraire de la commande ne peut pas se produire.
auto lhs = std::shared_ptr<Lhs>(new Lhs("foo"));
auto rhs = std::shared_ptr<Rhs>(new Rhs("bar"));
F(lhs, rhs);
La meilleure façon de résoudre ce cours est d'utiliser std::make_shared
à la place.
F(std::make_shared<Lhs>("foo"), std::make_shared<Rhs>("bar"));
Mise à jour II: l'Inconvénient de l' std::make_shared
Citant Caseycommentaires:
Depuis là, il n'y a qu'une seule allocation, le pointee du mémoire ne peut pas être libéré jusqu'à ce que le bloc de contrôle est plus en cours d'utilisation. Un weak_ptr
pouvez garder le contrôle de bloc en vie indéfiniment.
Pourquoi les instances de l' weak_ptr
s à garder le contrôle de bloc en vie?
Il doit y avoir un moyen pour weak_ptr
s pour déterminer si l'objet géré est toujours valide (par exemple. pour lock
). Ils font cela en vérifiant le nombre de shared_ptr
s propre à l'objet géré, qui est stocké dans le bloc de contrôle. Le résultat est que les blocs de contrôle sont en vie jusqu'à ce que l' shared_ptr
compter et de l' weak_ptr
comptent tous les deux frappé 0.
Retour à l' std::make_shared
Depuis std::make_shared
fait un seul tas-allocation pour le bloc de contrôle et de l'objet géré, il n'existe aucun moyen pour libérer de la mémoire pour le bloc de contrôle et de l'objet géré de manière indépendante. Nous devons attendre jusqu'à ce que nous pouvons libérer à la fois le bloc de contrôle et de la gestion de l'objet, qui se trouve être jusqu'à ce qu'il n'y a aucun shared_ptr
s ou weak_ptr
s vivant.
Supposons que nous avons effectuée au lieu de deux tas-allocations pour le bloc de contrôle et de l'objet géré par new
et shared_ptr
constructeur. Ensuite, nous libérer de la mémoire pour les objets gérés (peut-être plus tôt) lorsqu'il n'y a shared_ptr
s en vie, et de libérer de la mémoire pour le bloc de contrôle (peut-être plus tard) quand il n'y a aucun weak_ptr
s vivant.