Je veux effectuer des "copies profondes" d'un conteneur stl de Je sais sur le modèle em> prototype em> modèle de conception, mis en œuvre au moyen de L'idiome cors virtuel em>, comme expliqué dans le C ++ FAQ Lite, point 20.8 . une copie profonde est alors le suivant: p> Comme Andrei Alexandrescu State It : P> Le clone En outre, les clients de Ma question est la suivante: y a-t-il un autre façon de faire une classe de base abstraite clonable sans nécessiter de classes dérivées pour écrire le code associé à clone? (Classe d'assistance? Modèles?) P> Suivant est mon contexte. Espérons que cela aidera à comprendre ma question. P> Je concevra une hiérarchie de classe pour effectuer des opérations sur une classe plusieurs opérations multiples peuvent être effectuées. Séquentiellement sur une image: p> S'il y a plusieurs images, l'ensemble peut être divisé et partagé sur plusieurs threads. Pour assurer la "sécurité de thread-sécurité", chaque thread doit avoir sa copie édité: strong> La version thread-coffre-fort utilise le modèle de conception prototype pour appliquer la copie de pointe-des-objets em> - - NON PTRS: P>
C'est simple et simple: p> inconvénients h1>
() code> La mise en œuvre doit suivre le même motif dans toutes les classes dérivées; Malgré sa structure répétitive, il n'y a pas de moyen raisonnable d'automatiser la définition de la fonction de clone
code> (au-delà des macros, c'est-à-dire). P>
BlockQuote>
ABC code> peuvent éventuellement faire quelque chose de mauvais. (Je veux dire, rien n'empêche les clients à faire quelque chose de mal, alors, il sera em> arriver.) P>
Meilleur design? H1>
image code>: p>
imgop code>: p>
v code> -
v code> devient un prototype à être copié en profondeur dans chaque fil. P>
struct ImgOp
{
virtual ~ImgOp() {}
bool run( Image & ) = 0;
virtual ImgOp * clone() = 0; // virtual ctor
};
struct CheckImageSize : public ImgOp { /* no clone code */ };
struct CheckImageResolution : public ImgOp { /* no clone code */ };
struct RotateImage : public ImgOp { /* no clone code */ };
bool do_operations( vector< ImgOp* > v, Image &i )
{
// In another thread
vector< ImgOp* > v2;
transform( v.begin(), v.end(), // Copy pointed-to-
back_inserter( v2 ), mem_fun( &ImgOp::clone ) ); // objects
for_each( v.begin(), v.end(),
/* bind2nd( mem_fun( &ImgOp::run ), i ... ) don't remember syntax */ );
}
3 Réponses :
Vous pouvez utiliser le motif curieusement récursif mais cela pourrait rendre votre code moins lisible.
Vous aurez toujours besoin de constructeurs de copies. Cela fonctionne comme suit.
+1 bonne approche. Comme indiqué dans l'article Tyler mentionné dans un commentaire, vous n'avez plus de type de retour covariant. Je n'ai jamais compris pourquoi c'était si gros problème. Les endroits où j'appellerais une méthode de clone, je ne connais pas de toute façon le type dérivé.
Si je comprends bien, cela ne fonctionnera pas si j'ai besoin de sous-classement SOMABCIMPL code>, non?
J'ai pensé à cette solution mais le rejeté car le client doit toujours écrire un code associé à clone: le paramètre de modèle de clonableabc code>. Du point de vue du client, l'intention de ce paramètre de modèle n'est pas claire et pourrait sembler inutile.
doublep> en effet. Pas avec ce morceau de code. Julien L.> Je comprends votre choix. Cela pourrait être un peu trompeur pour le client.
Une copie profonde est alors: [pour la boucle] p>
Vous faites cloner le client le vecteur explicitement. Je ne sais pas si cela répond à votre question, mais je suggérerais un vecteur de pointeurs intelligents afin que le clonage se produise automatiquement. P>
xxx pré> Bien sûr, vous ne voulez pas ces Des copies implicites se produisent lors du redimensionnement d'un vecteur ou de quelque chose, vous devez donc pouvoir distinguer des copies des mouvements. Voici mon implémentation de jouet C ++ 0x de
cloning_pointer code> que vous pourriez avoir à ajuster à vos besoins. P>
xxx pré> julien:
&& < / CODE> N'EST PAS UNE "REF DE REF", il s'agit d'une référence de rvalue qui se lie uniquement à des avalues modifiables. Voir cet excellent (mais tristement légèrement obsolète) tutoriel et VIDEO Pour un aperçu des références de rvalue et de la façon dont ils fonctionnent. P> blockQquote>
C'est intéressant. S'il vous plaît, pouvez-vous donner plus de détails sur le mécanisme "déménagement": comment le cloning_pointer sait-il qu'il doit bouger et non cloné? Chaque fois, il reçoit une ref de référence, cela signifie qu'il est redimensionné? BTW, vous ne devez pas utiliser std :: swap () code> mais `utiliser std :: échange; échanger().
@Julien Je sais sur le swap idiome, mais je pense qu'il est assez sûr d'échanger deux pointeurs bruts avec std :: échangez code> ;-) J'ai inclus deux liens pour vous qui expliquent assez bien le mécanisme de déménagement.
Merci beaucoup pour les détails (et pour la correction de swap :) J'aime la classe d'assistance cloning_pointer code> car cela rend l'intention claire. Cependant, il ne résout pas mon problème car les classes dérivées doivent toujours mettre en œuvre la méthode
clone () code>.
@Julien, vous êtes la bienvenu. En ce qui concerne le swap, ce n'était pas vraiment une "correction" de ma part ... Je suppose que je n'étais que paresseux :-) En règle générale, l'idiome que vous avez décrit devrait certainement être préféré.
FYI, c'est la conception que je suis sorti. Merci Paul et Fredoverflow pour vos intrants. (Et Martin York pour votre commentaire.)
polymorphisme est effectué à l'aide de modèles et interfaces implicites em>: P> CheckImageSize op1;
op1.w = ...; // Fine
op1.h = ...;
CheckImageResolution op2;
// ...
vector< ImgOpCloner > v;
v.push_back( ImgOpCloner( op1 ) ); // This looks like a smart-ptr, this is not
v.push_back( ImgOpCloner( op2 ) ); // confusing anymore -- and intent is clear
Je dirais qu'il est en fait possible d'automatiser
clone () code> (si un peu inélégant): nerdland.net/2009/06/...
@Tyler Mchenry: Mais la fabrication automatique encouragerait la mauvaise utilisation, puis C ++ commencerait à ressembler à Java. Je dirais que presque tous les usages de clone () ont tort (dans les quelques cas où il est nécessaire, laissez les gens faire le travail de la mettre en œuvre) comme malheureusement, c'est un moyen simple à utiliser de manière incorrecte, ce qui entraîne une mauvaise conception et une mauvaise mise en œuvre.
Quel est le problème avec simplement définir et utiliser le constructeur de copie comme il était censé? Comme @Martin dit, vous ne voulez absolument pas que des objets soient traitablement claquables.