Question

J'utilise généralement un boost :: scoped_ptr pour les pimpl (pour une raison parce que je n'ai pas de surprise si j'oublie de traiter avec le constructeur de copie)

Cependant, avec les modèles, je ne peux pas simplement mettre le destructeur dans le fichier cpp où l'impl est entièrement défini afin de répondre aux exigences du destructeur de scoped_ptr.Cela fonctionne de toute façon, mais je ne sais pas si c'est garanti pour fonctionner ou juste par hasard.Existe-t-il des «meilleures pratiques» ou des normes?Scoped_ptr est-il le meilleur pointeur intelligent pour les pimpls dans les classes non copiables?

template <class T> class C {
public:
    C(){}
    ~C(){}
private:
    boost::scoped_ptr<T> pimpl_;
};
Était-ce utile?

La solution

boost::shared_ptr ne nécessite pas de définition complète autre que à le point d'instanciation - dans le constructeur, dans le cas d'un bouton.boost::shared_ptr n'est pas approprié pour l'idiome pimpl, cependant, puisqu'il donne une sémantique très inattendue (sémantique de référence pour cession ou copie);si vous voulez vraiment la complexité supplémentaire d'un pointeur intelligent, boost::scoped_ptr serait plus approprié (mais il nécessite une définition complète au moment où son destructeur est instancié).

En ce qui concerne les modèles, cela n'a aucun sens d'utiliser l'idiome pimpl pour les détails d'implémentation de l'en-tête.En l'absence de export, tous les détails d'implémentation d'un modèle de classe doivent être inclus partout où le modèle est utilisé, donc la motivation derrière le bouton l'idiome cesse d'exister.

Autres conseils

Il se trouve qu'Herb Sutter a recommencé à écrire ses GotW après un long moment.L'un des premiers nouveaux est lié aux "Pare-feu de compilation".

Vous voudrez peut-être jeter un œil à:

GotW # 100: Pare-feu de compilation (difficulté: 6/10)

et

GotW # 101: Pare-feu de compilation, partie 2 (difficulté: 8/10)

Deux ans plus tard, je comprends beaucoup mieux la situation, dans l'intérêt de garder les réponses de dépassement de pile pertinentes et à jour, voici comment je répondrais à la question aujourd'hui.

La prémisse de ma question initiale est quelque peu erronée. La raison d'utiliser l'idiome pimpl est de masquer les détails d'implémentation du compilateur. Cela se fait en stockant l'implémentation via un pointeur opaque (pointeur vers un type de données déclaré mais non défini). Cela peut réduire considérablement la quantité d'en-têtes nécessaires aux autres unités de compilation qui interagissent avec la classe et ainsi accélérer le temps de compilation. Dans le cas du modèle dans ma question, il est nécessaire que le type T soit pleinement connu au point d'instanciation, ce qui en pratique nécessite que le type de impl soit entièrement défini partout où C<ImplType> est utilisé, ce qui en fait clairement pas un exemple de l'idiome pimpl au sens classique du terme.

Il y a d'autres raisons de conserver les données d'une classe via un pointeur privé, par exemple, cela permet une implémentation facile du mouvement et de l'échange sans jet et est également utile si votre classe doit remplir une garantie d'exception forte (voir copie et échange idiome Qu'est-ce que l'idiome copier-échanger? ). D'autre part, il ajoute une couche d'indirection (entraînant souvent un échec de cache) sur chaque accès à l'impl et une allocation / désallocation de tas lors de la création et de la destruction de l'impl. Celles-ci peuvent être des pénalités de performance substantielles, par conséquent cette solution ne doit pas être considérée comme une solution miracle.

Si vous pouvez utiliser C ++ 11, std :: unique_ptr doit être utilisé à la place de boost :: scoped_ptr.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top