C++ à l'aide de scoped_ptr comme une variable membre
Voulais juste des avis sur une question de conception. Si vous avez une classe C++ que possède d'autres objets, seriez-vous d'utiliser des pointeurs intelligents pour y parvenir?
class Example {
public:
//...
private:
boost::scoped_ptr<Owned> data;
};
La "Propriété" de l'objet ne peut pas être stockée en valeur car il peut changer à travers la durée de vie de l'objet.
Mon point de vue, c'est que d'un côté, vous faites, il est clair que l'objet est la propriété et de s'assurer de sa suppression, mais sur le revers de la médaille, vous peut facilement avoir un pointeur normal et delete dans le destructeur. Est-ce exagéré?
Suivi: voulais Juste dire merci pour toutes vos réponses. Merci pour le heads-up sur auto_ptr laissant l'autre objet avec un pointeur NULL lorsque l'ensemble de l'objet est copié, j'ai utilisé auto_ptr approfondie, mais n'avait pas pensé à ça pour l'instant. Je fais essentiellement toutes mes classes, boost::noncopyable à moins que j'ai une bonne raison, donc il n'y a rien à craindre à ce sujet là. Et merci aussi pour les informations sur les fuites de mémoire dans les exceptions, c'est bon à savoir aussi. J'essaie de ne pas écrire des choses qui pourraient causer des exceptions dans le constructeur de toute façon - il y a de meilleures façons de le faire -, de sorte que ne devrait pas être un problème.
J'ai juste eu une autre question si. Ce que je voulais quand j'ai posé cette question était de savoir si quelqu'un fait cela, et vous semblez tous oublier que c'est une bonne idée en théorie, mais personne ne dit qu'ils sont amenés à le faire. Ce qui me surprend! Certainement un objet de la possession d'un pointeur à un autre n'est pas une idée nouvelle, je me serais attendu à vous tous l'aurait fait avant, à un certain point. Ce qui se passe?
- "J'essaie de ne pas écrire des choses qui pourraient causer des exceptions dans le constructeur de toute façon - il y a de meilleures façons de le faire" - j'ai un problème avec cette déclaration. Souvent, la levée d'une exception à partir d'un constructeur est le meilleur moyen d'indiquer qu'une classe ne peut pas être construit.
Vous devez vous connecter pour publier un commentaire.
C'est une bonne idée. Il permet de simplifier votre code, et de s'assurer que lorsque vous modifiez la Propriété de l'objet pendant la durée de vie de l'objet, la précédente est détruit correctement.
Vous devez vous rappeler que scoped_ptr est noncopyable, cependant, ce qui rend votre classe noncopyable par défaut jusqu'à ce que vous ajoutez votre propre constructeur de copie, etc. (Bien sûr, en utilisant le constructeur de copie par défaut dans le cas de crue pointeurs serait un non-pas de trop!)
Si votre classe a plus d'un pointeur de champ, l'utilisation de scoped_ptr améliore réellement exception de sécurité dans un cas:
Maintenant, imaginez que, pendant la construction d'un C le deuxième "nouvelle Propriété" déclenche une exception (de mémoire, par exemple). o1 sera coulé, parce que C::~C() (le destructeur) ne sont pas appelés, parce que l'objet n'a pas été entièrement construit encore. Le destructeur de tout entièrement construit champ de membre ne obtenir appelle, bien que. Donc, à l'aide d'un scoped_ptr au lieu d'un simple pointeur permettra o1 à être détruits de façon appropriée.
scoped_ptr est très bonne pour ce but. Mais on doit comprendre sa sémantique. Vous pouvez regrouper des pointeurs intelligents à l'aide de deux propriétés principales:
C'est plutôt une terminologie commune. Pour les pointeurs intelligents, il y a une terminologie spécifique qui marque ces propriétés:
Laisser du groupe la disposition des pointeurs intelligents, à l'aide de
(C)opyable
, et(M)ovable
,(N)either
:boost::scoped_ptr
: Nstd::auto_ptr
: Mboost::shared_ptr
: Cauto_ptr
a un gros problème, en ce qu'il réalise les Meubles concept à l'aide d'un constructeur de copie. C'est parce que Quand auto_ptr a été accepté en C++, il n'y avait pas encore une façon de supporter nativement la sémantique de déplacement à l'aide d'un constructeur de déplacement, par opposition à la nouvelle Norme C++. Qui est, vous pouvez effectuer les opérations suivantes avec auto_ptr, et ça fonctionne:De toute façon, comme nous le voyons, dans votre cas, vous ne serez pas en mesure de transférer la propriété d'un autre objet: Votre objet sera en effet la non-copiable. Et dans la prochaine Norme C++, il sera non délocalisables si vous restez avec scoped_ptr.
Pour la mise en œuvre de votre classe avec scoped_ptr, montre que vous avez un de ces deux points de satisfaits:
Owned
complètement définit la classe.Sinon, lorsque vous créez un objet de Exemple, le compilateur aurait implicitement définir un destructeur pour vous, qui appellent scoped_ptr du destructeur:
Cela ferait alors scoped_ptr appel
boost::checked_delete
, qui se plaignaient deOwned
étant incomplète, dans le cas où vous n'avez pas fait de ces deux points. Si vous avez défini votre propre dtor dans le .fichier cpp, l'appel implicite pour le destructeur de scoped_ptr serait faite à partir de l' .fichier cpp, dans lequel vous pouvez placer la définition de votreOwned
classe.Vous avez le même problème avec auto_ptr, mais vous avez un problème de plus: Fournir de l'auto_ptr incomplète, ce type est un comportement indéfini actuellement (peut-être que cela sera corrigé pour la prochaine version C++). Donc, lorsque vous utilisez auto_ptr, vous ont à faire de la Propriété un type complètes dans votre fichier d'en-tête.
shared_ptr n'ont pas ce problème, car il utilise une polymorphes deleter, qui fait un appel indirect à la supprimer. De sorte que la suppression de la fonction n'est pas instancié à la fois le destructeur est instancié, mais à l'époque, la deleter est créé dans shared_ptr du constructeur.
Il n'est pas exagéré du tout, c'est une bonne idée.
Il n'a besoin de votre classe que les clients sachent à propos de boost, si. Cela peut ou peut ne pas être un problème. Pour la portabilité, vous pourriez envisager de std::auto_ptr qui n' (dans ce cas) le même travail. Comme c'est privé, vous n'avez pas à vous soucier d'autres personnes qui tentent de le copier.
À l'aide de la scoped_ptr est une bonne idée.
Garder manuellement et de détruire le pointeur n'est pas aussi simple que vous le pensez. Surtout si il n'y a plus d'un pointeur BRUT dans votre code. Si une exception de sécurité et pas de fuite de mémoire est une priorité, alors vous avez besoin de beaucoup de code supplémentaire pour l'obtenir correcte.
Pour commencer, vous devez assurez-vous de bien définir tous les quatre méthodes par défaut. C'est parce que le compilateur a généré version de ces méthodes sont très bien pour les objets normaux (y compris les pointeurs intelligents), mais dans le cas normal, conduira à des problèmes avec le pointeur de la manipulation (Cherchez le peu de Problème de Copie).
Si vous utilisez le scoped_ptr alors vous n'avez pas besoin de s'inquiéter à propos de l'un de ceux-ci.
Maintenant, si vous avez plus d'un pointeur BRUT dans votre classe (ou d'autres parties de votre constructeur peut les jeter) . Vous devez EXPLICITEMENT traiter les exceptions au cours de la construction et de la destruction.
Regardez comment beaucoup plus facile une scopted_ptr est.
Étendue pointeurs sont bons pour exactement ce parce qu'ils s'assurer que les objets sont supprimés sans que vous ayez à vous en préoccuper en tant que programmeur. Je pense que c'est une bonne utilisation de l'étendue ptr.
Je trouve qu'une bonne stratégie de design en général est d'éviter la libération de la mémoire manuellement, autant que possible, et laissez vos outils (dans ce cas des pointeurs intelligents) de le faire pour vous. La suppression manuelle est mauvais pour une raison que je peux voir, c'est que le code devient difficile de maintenir très rapidement. La logique de l'allocation et la désallocation de la mémoire est souvent distinct dans le code, et qui conduit à la complémentarité des lignes de maintenir l'ensemble.
Je ne pense pas que c'est exagéré, c'documents de la sémantique des états beaucoup mieux que d'avoir un pointeur brut et est moins sujette aux erreurs.
Pourquoi inutile? boost::scoped_ptr est très facile à optimiser, et je parie que la résultante de la machine de code serait le même que si vous supprimez manuellement le pointeur dans le destructeur.
scoped_ptr est bon, juste l'utiliser 🙂