J'utilise une vieille bibliothèque open source, avec l'API d'intérêt suivant (simplifié):
// some class that holds a raw pointer to memory on the heap // DOES NOT delete it in its destructor // DOES NOT do a "deep" copy when copied/assigned (i.e., after copying both objects // will point to the same address) class Point; // function used to construct a point and allocate its data on the heap Point AllocPoint(); // function used to release the memory of the point's data void DeallocPoint(Point& p); // Receives a pointer/c-array of Points, along with the number of points // Doesn't own the memory void Foo(Point* points, int npts);
5 Réponses :
"Vous" pourrait écrire un wrapper simple pour libérer la mémoire: mais cela semble un peu "adhoc". Quelle est une solution plus standard / réutilisable? P> p>
:-( en.wikipedia.org/wiki/rule_of_three_%28C%2B % 2b_programming% 2 9 Veuillez éditer votre code pour supprimer le danger
S'il illustre le point assez bien, devons-nous fournir des solutions complètes et sûres à tout pour chaque question? NE PEUT-NOUS NE PEUVENT NE PEUVER-ÊTRE SUR LE PLUS SUR LA MISE EN PARTICIPE INTERNEE ET SAFE?
@Balogpal, en effet, comme dit Matthew Walton, je voulais illustrer le point avec un petit fouillard possible. Néanmoins j'ai édité le code.
Je suis avec Fred Brown ici, seul un imbécile quitte un pistolet chargé dans les mains d'un enfant. Toute personne a la possibilité de ne pas poster la réponse, ceux qui le feront de bonne qualité. Une enveloppe destinée au remplacement de l'original doit fonctionner de la même manière, introduisant un comportement indéfini après une copie essentielle.
@Balogpal je suis d'accord avec vous, mais cela est maintenant fixé après la modification, n'est-ce pas?
@Johnnyw: Pour le compte rendu, le code nécessaire pour l'exactitude n'est pas encombré
Et comment remplissez-vous le vecteur code>? Cela pourrait être un point critique.
Copier un point fait une copie "peu profonde" du pointeur qu'un point détient, de sorte que vous pourriez juste faire des points.Push_back (allocpoint ())
@Johnnyw éventuellement. Ou simplement créer une fonction pointvectorwrapper :: push_back () code> (aucun argument), car il n'y a qu'une seule valeur que vous pouvez réellement repousser. Mais de manière réaliste, il doit y avoir des fonctions supplémentaires qui devraient être appelées (et exposées).
Si vous voulez vraiment faire semblant bien, vous allez probablement devoir écrire un ensemble de wrappers vraiment complets qui cachent complètement l'API de la bibliothèque - efficacement, enveloppez toute la bibliothèque avec une manière qui se comporte de manière moderne C ++ à l'extérieur et cache tout le désordre à l'intérieur. P>
Pas une tâche agréable, mais si vous pouvez obtenir le comportement de cette bibliothèque à droite, il faut que votre vie soit beaucoup plus facile à long terme. Pourrait ne pas valoir la peine si vous n'utilisez pas très largement cette bibliothèque externe. P>
J'envelopperais cette API de type non-Raii dans des blocs de construction Par exemple: Vous pouvez définir une classe alors vous pouvez simplement utiliser un (Ceci est une approche General EM> que vous pouvez utiliser lorsque vous souhaitez utiliser C Bibliothèques C dans le code C ++ moderne: Vous pouvez envelopper les poignées de la bibliothèque C et les objets de la bibliothèque C bruts des limites de sécurité Raii et Utilisez ces classes d'emballage sécurisées robustes dans votre code C ++ moderne.) P> raipoinx code> qui enveloppe la classe (non-Raii)
class code> et dans ses appels de constructeur
allocpoint () Code>, dans le destructeur
dealLocPoint () code>. Ensuite, vous pouvez définir une bonne copie constructeur et copier
opérateur = code> ou simplement implémenter déplacer la sémantique (avec le constructeur de déplacement et déplacer
opérateur = code>) ou faire la classe wrapper à la fois copiable et mobile. , basant sur vos besoins. P>
std :: vecteur
Le problème avec c'est qu'il ne peut pas passer un raipoint * code> à ses fonctions. Il devrait envelopper chacune des fonctions pertinentes avec une fonction qui extrait le point
code> et le transmet. (Il n'est pas non plus clair que peut i> implémenter une copie correcte ou déplacer la sémantique.)
Je pourrais aussi utiliser uniques_ptr avec un Delier personnalisé, mais il y a un problème ici concernant l'utilisation: je ne pourrai pas passer des points.Data () à la fonction (car il retournera RaiPoint * et pas point * comme accepté de FOO )
@Jameskanze: La classe Wrapper Raii pourrait exposer un get () code> ou
getPtr () code> méthode renvoyant un point
point * code> pour interfacer avec l'API héritée.
@ M.C64 Cette fonction nécessite un pointeur sur un tableau de points code>. Pas un tableau de
PIN RAII code>. Être capable de convertir un seul
point code> ne l'aide pas beaucoup.
Comme @jameskanze a souligné (me précédant dans 32 secondes dans le premier commentaire :), j'ai besoin d'un point *.
@Johnnyw Plus important encore, vous avez besoin d'un point * code> qui pointe vers le premier élément d'un tableau de points
point code> et non à un seul
point code>. Plutôt que de définir un
raipoint code>, vous devez probablement définir un
pointvector code>, qui maintient un
std :: vecteur
point code>.
Enroulez toujours le I> RAW i> Point CODE> Ressource dans un RAII B> a du sens. Ensuite, il est possible de stocker ces ressources enveloppées en toute sécurité dans un
std :: vecteur code> (qui possède i>
raipoint code> s) et construisez une seconde Observation i>
std :: vecteur
.Data () code> et
.Size () code> méthodes.
vous peut em> utiliser Si le vecteur doit réellement posséder les points, vous pouvez envelopper
dans une classe plus complexe, qui appelle std :: vecteur
foo (& v [0],
v.Size ()) code>. Mais la gestion de la mémoire ici pourrait être délicate,
puisque
point code> apparemment ne fournit aucune copie propre et
mission; Un Delier personnalisé dans l'allocator sera appelé pour
chaque élément, même s'il est copié. p>
allocpoint code> pour chaque
insertion (et insère les résultats) et
dealLocpoint code> pour chaque
retrait (et pour tout rester dans le vecteur sur
destruction). Cette classe devrait pas em> permettre l'accès à l'écriture à la
point code> (non-const
opérateur [] code>, itérateurs non-constitués, etc.),
Cependant, comme cela permettrait de changer tous les pointeurs de
point code> et perdre ce qui est nécessaire pour
dealLocpoint code> pour fonctionner
correctement. Probablement, il y a d'autres fonctions pour manipuler
point code>; Vous devrez organiser pour que cela soit disponible
à travers l'interface wrapper. p>
Vous pouvez utiliser un vecteur standard avec un allocator personnalisé, invoqué AllocPoint sur la méthode de construction et la translocpoint () sur la méthode destruct.
template<typename T> class CustomAllocator : public std::allocator<T> { //Rebind and constructors }; template<> class CustomAllocator<Point> : public std::allocator<Point> { //Rebind and constructors //For c++11 void construct( pointer p ) { new (p) Point(); *p = AllocPoint(); } void construct( pointer p, const_reference val ) { construct(p); //copy member from val to point if neccessary }; void destroy( pointer p ) { DeallocPoint(*p); p->~Point(); } }; typedef std::vector<Point, CustomAllocator<Point> > PointVector;
Regardez le Boost Pointeur Conteur de la bibliothèque a >.
Une chose qui vient à l'esprit est "fossé la bibliothèque". Sérieusement.
Malheureusement, ce n'est pas une option pour moi ...
"Parce que je ne pourrai pas utiliser la fonction
foo code>" - pourquoi pas?
std :: unique_ptr :: obtenir code> vous donnera un pointeur brut tout en conservant la propriété.
Oui, mais pour utiliser FOO j'ai besoin d'un C-Array i> de points, alors comment puis-je passer tous les points du vecteur?
@juanchopanza C'est en effet une très bonne solution! Merci