6
votes

Vecteur intelligent pour les pointeurs bruts en C ++ 11?

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 :


1
votes

"Vous" pourrait écrire un wrapper simple pour libérer la mémoire: xxx

mais cela semble un peu "adhoc". Quelle est une solution plus standard / réutilisable?


9 commentaires

:-( 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 ? 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 () (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).



4
votes

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.

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.


0 commentaires

4
votes

J'envelopperais cette API de type non-Raii dans des blocs de construction Raii , puis utilisez-les dans C ++ 11 Code.

Par exemple: Vous pouvez définir une classe raipoinx qui enveloppe la classe (non-Raii) class et dans ses appels de constructeur allocpoint () , dans le destructeur dealLocPoint () . Ensuite, vous pouvez définir une bonne copie constructeur et copier opérateur = ou simplement implémenter déplacer la sémantique (avec le constructeur de déplacement et déplacer opérateur = ) ou faire la classe wrapper à la fois copiable et mobile. , basant sur vos besoins.

alors vous pouvez simplement utiliser un std :: vecteur avec votre classe wrapper basée sur Raii.

(Ceci est une approche General 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.)


7 commentaires

Le problème avec c'est qu'il ne peut pas passer un raipoint * à ses fonctions. Il devrait envelopper chacune des fonctions pertinentes avec une fonction qui extrait le point et le transmet. (Il n'est pas non plus clair que peut 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 () ou getPtr () méthode renvoyant un point point * pour interfacer avec l'API héritée.


@ M.C64 Cette fonction nécessite un pointeur sur un tableau de points . Pas un tableau de PIN RAII . Être capable de convertir un seul point 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 * qui pointe vers le premier élément d'un tableau de points point et non à un seul point . Plutôt que de définir un raipoint , vous devez probablement définir un pointvector , qui maintient un std :: vecteur , mais garantit tous La gestion nécessaire de l'individu point .


Enroulez toujours le RAW Point Ressource dans un RAII a du sens. Ensuite, il est possible de stocker ces ressources enveloppées en toute sécurité dans un std :: vecteur (qui possède raipoint s) et construisez une seconde Observation std :: vecteur , qui peut être transmis à l'API héritée à l'aide de .Data () et .Size () méthodes.



4
votes

vous peut utiliser std :: vecteur , appelant foo (& v [0], v.Size ()) . Mais la gestion de la mémoire ici pourrait être délicate, puisque point 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é.

Si le vecteur doit réellement posséder les points, vous pouvez envelopper dans une classe plus complexe, qui appelle allocpoint pour chaque insertion (et insère les résultats) et dealLocpoint pour chaque retrait (et pour tout rester dans le vecteur sur destruction). Cette classe devrait pas permettre l'accès à l'écriture à la point (non-const opérateur [] , itérateurs non-constitués, etc.), Cependant, comme cela permettrait de changer tous les pointeurs de point et perdre ce qui est nécessaire pour dealLocpoint pour fonctionner correctement. Probablement, il y a d'autres fonctions pour manipuler point ; Vous devrez organiser pour que cela soit disponible à travers l'interface wrapper.


0 commentaires

1
votes

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;


0 commentaires