Dois-je utiliser shared_ptr ou unique_ptr
J'ai fait quelques objets à l'aide de la pimpl idiome, mais je ne suis pas sûr que d'utiliser std::shared_ptr
ou std::unique_ptr
.
Je comprends que std::unique_ptr
est plus efficace, mais ce n'est pas tellement un problème pour moi, car ces objets sont relativement lourds, de sorte que les coûts de std::shared_ptr
sur std::unique_ptr
est relativement mineur.
Je suis actuellement en cours avec std::shared_ptr
juste à cause de la plus grande flexibilité d'utilisation. Par exemple, à l'aide d'un std::shared_ptr
me permet de stocker ces objets dans une table de hachage pour un accès rapide tout en étant capable de retourner les copies de ces objets pour les appelants (comme je le crois, tout itérateurs ou références peuvent rapidement devenir invalide).
Cependant, ces objets ne sont vraiment pas être copié, que les modifications portent sur l'ensemble des copies, donc je me demandais que peut-être l'aide d' std::shared_ptr
et permettant des copies est une sorte d'anti-modèle ou une mauvaise chose.
Est-ce correct?
- À l'aide de l'une ou l'autre change profondément la sémantique de copie que vous donnez à vos objets. Il y a utilise pour les deux. Je dirais que le plus idiomatique dans le C++ monde est
unique_ptr
, mais l'objet qui partagent un implémentations ont à leur utilisation, en particulier si vous êtes l'écriture de "l'étranger" de code (par exemple. COM, C++/CLI), ou si la classe ressemble vraiment à un "type de référence". - Question similaire: stackoverflow.com/questions/311166/...
- La manière recommandée en C++11 est à usage unique, après tout, vous n'avez pas besoin de copier ou partager l'application avec n'importe qui. Aussi unique_ptr est plus rapide au moment de l'exécution.
Vous devez vous connecter pour publier un commentaire.
Certainement
unique_ptr
ouscoped_ptr
.Pimpl
n'est pas un modèle, mais un idiome, qui traite de la compilation de la dépendance du temps et de la compatibilité binaire. Il ne devrait pas affecter la sémantique des objets, en particulier en ce qui concerne sa copie comportement.Vous pouvez utiliser quel que soit le type de pointeur intelligent que vous voulez sous le capot, mais ces 2 la garantie que vous ne serez pas accidentellement partager la mise en œuvre entre deux objets distincts, car ils nécessitent une décision consciente à propos de la mise en œuvre du constructeur de copie et l'opérateur d'affectation.
Il n'est pas un anti-modèle, en fait, il s'agit d'un modèle: l'Aliasing. Vous utilisez déjà, en C++, avec les pointeurs et références.
shared_ptr
offrent une mesure de "sécurité" pour éviter les morts références, au coût supplémentaire de complexité et de nouvelles questions (attention aux cycles de créer des fuites de mémoire).Sans rapport avec Pimpl
Si vous pouvez tenir compte de l'état, vous pouvez prendre un coup d'oeil à la Poids mouche modèle.
shared_ptr
, en fait. Vous voudrez peut-être un objetFoo
dont la mise en œuvre peut être partagée entre plusieursFoo
objets, à l'aide de comptage de référence et de copie sur écriture de la sémantique.shared_ptr
a été adapté à certains cas), mais nous parlions de Pimpl ici; ce n'est pas un de ces cas oùshared_ptr
est adapté.Si vous utilisez
shared_ptr
, ce n'est pas vraiment le classique pimplidiome (à moins que vous prendre des mesures supplémentaires). Mais la vraie question
c'est pourquoi vous voulez utiliser un pointeur intelligent pour commencer; c'est très
clair où l'
delete
devrait se produire, et il n'y a pas de problème deexception de sécurité ou d'autres à être concernés par. Tout au plus,
un pointeur intelligent vous permettra d'économiser en une ou deux lignes de code. Et la
seul à la sémantique correcte est
boost::scoped_ptr
,et je ne pense pas que cela fonctionne dans ce cas. (IIRC, il nécessite
un type complètes pour être instancié, mais je pourrais être
mal.)
Un aspect important de la pimpl idiome est que son utilisation devrait être
transparent pour le client; la classe doit se comporter exactement comme si
il ont été mises en œuvre de façon classique. Cela signifie soit en inhibant la
copie et de la cession ou de la mise en œuvre de copie en profondeur, à moins que la classe
est immuable (pas de non-const fonctions de membre). Aucun d'habitude
pointeurs intelligents mettre en œuvre copie en profondeur; vous pourriez mettre en œuvre, de
bien sûr, mais il serait sans doute encore besoin d'une complète type
chaque fois que la copie se passe, ce qui signifie que vous auriez toujours se
fournir à un utilisateur défini constructeur de copie et l'opérateur d'affectation
(puisqu'ils ne peuvent pas être en ligne). Compte tenu de cela, il n'est probablement pas
vaut la peine en utilisant le pointeur intelligent.
Une exception est si les objets sont immuables. Dans ce cas, il
n'a pas d'importance si la copie est profonde ou pas, et
shared_ptr
les poignées de la situation complètement.
Lorsque vous utilisez un
shared_ptr
(par exemple dans un récipient, puis de regarder cela et le retourner par valeur), vous ne sont pas la cause d'une copie de l'objet et il points de, simplement une copie du pointeur avec un nombre de références.Cela signifie que si vous modifiez l'objet sous-jacent à partir de plusieurs points, alors vous influer sur les changements sur le même instance. C'est exactement ce qu'il est conçu, donc pas certains anti-modèle!
Lors du passage d'un
shared_ptr
(comme les commentaires dire) c'est mieux de passer par référence const et copie (il y en incrémentant le nombre de références) en cas de besoin. Comme pour le retour, au cas par cas.shared_ptr
ouunique_ptr
. Dans ce contexte, la smart pointeur lui-même ne devrait pas être passé autour.Oui, veuillez les utiliser. Il suffit de mettre, le shared_ptr est une implémentation de pointeur intelligent. unique_ptr est une mise en œuvre automatique de pointeur: