6
votes

Emballage abstrait pour les conteneurs STL?

Je voudrais exposer certains objets sous forme de récipients abstraits avec des possibilités de manipulation de style stl (pour les boucles de protection, itérateurs) et masquer les détails de la mise en œuvre du conteneur.

Les problèmes de performance ne comptent pas (appels virtuels et même une allocation de mémoire lors de la copie «Universal» Itérateur sont acceptables).

Je vais écrire une interface de conteneur abstrait avec des fonctions virtuelles pures (+ "universel" itérateur sur le conteneur) et un adaptateur d'implémentation pour les conteneurs séquentiels STL.

Mais peut-être que des bibliothèques existantes sont utiles à cet effet?

ou c'est totalement une mauvaise idée?


9 commentaires

Quel serait l'avantage gagné que vous ne pouviez pas mettre en œuvre avec des conteneurs STL sous-jacents? En C ++ 0x, le mot clé peut être utilisé pour impliquer le type d'itérateur correct pour un conteneur par la rvalue mais cela peut ne pas suffire à vos besoins.


Pourquoi voulez-vous faire cela? Les conteneurs STL font des tâches différentes avec une garantie de performance différente, si vous ne vous dérangeez pas de performance, vous ne devez pas créer un "conteneur universel", mais utilisez simplement std :: vecteur.


@ AJG85, @ Alessandro Teruzzi: Je ne veux pas recompiler le code "Client" lorsque l'implémentation décide de modifier le conteneur (par exemple) de Vector à Deque. Stl utilisé ici comme standard connu pour la manipulation des conteneurs, pas pour des performances maximales


Votre tentative d'écrire un conteneur Pimp. Scott Myers a une discussion sur cela dans l'un de ses livres. Même si les conteneurs sont très génériques en raison de la mise en œuvre sous-jacente, elles ne sont pas simplement coupées / coller remplaçables. c'est à dire. Vous ne pouvez pas remplacer un vecteur avec une carte sans travailler supplémentaire.


@user STL est en fait connu pour la performance. Vous avez peut-être besoin d'une interface commune entre la mise en œuvre du client et du serveur pour découpler des changements de backend du client avant?


@ AJG85 Oui, j'ai besoin d'une interface commune. Mais je suppose que cela est pratique pour l'utilisateur d'avoir une interface qui peut être utilisée avec des motifs bien connus communs ou des algorithmes stl simples comme pour


@Martin: Semble que vous êtes une rigidité, il y a des problèmes pour généraliser tous les conteneurs STL. Cependant, j'ai moins d'ambias pour généraliser au moins des conteneurs séquentiels à l'esprit (vecteur. Klist, déséquilibre) avec une simple possibilité d'itération


+1 Pour une question qui me dérange depuis longtemps. Je veux aussi avoir le pouvoir des itérateurs de style Java aussi. J'ai enveloppé une décision de conception Java dans l'itérateur classique C ++ à l'aide de la technique de clone et de Pimpl idiom, mais cela semble laid.


Juste un peu de note: une fois que vous avez obtenu les itérateurs généralisés, vous pouvez utiliser des gammes simples (comme Boost's iTerator_Range) pour vous envelopper des conteneurs uniformément.


5 Réponses :


1
votes

Si vos "objets" ne sont pas des objets stl mais ceux personnalisés, je pense que c'est une bonne idée.

Comme vous pouvez le voir sur http://www.sgi.com/tech/stl/vector.html , vecteur" est un modèle de "RandomAccessContainer. La plupart des packages de boost utilisent des concepts similaires (le terme réellement est "concept")

en C ++, vous avez deux possibilités de faire ceci:

  • une classe abstraite (interface) comme vous l'avez suggéré
  • Modèles

    avec des modèles que vous pouvez faire quelque chose comme: xxx

    • Tout cours qui fournit un itérateur, commence et finira fonctionnera: STD :: Vecteur, mais aussi vos propres objets.
    • Ces objets n'ont pas à hériter d'une interface, STD :: vecteur sera travail.

1 commentaires

Mes objets peuvent être ou ne peuvent pas être des objets STL, je souhaite cacher ce fait à la compilation du code du client pour fournir la liberté de modifier le conteneur de mise en œuvre sans forcer le code client à recompiler. Je voudrais donc obtenir une classe abstraite (interface) qui est un modèle de RandomAccessContainer et un adaptateur de mise en œuvre pour un conteneur particulier (STL possible possible) qui implémente une telle interface



1
votes

Voici mon avenir wrapper itérateur pour le style Java implémenté un. C'est moche. Les pièces de boost sont facultatives une pourraient être refactées.


0 commentaires

0
votes

La solution la plus générique au problème de "Exposer une classe C ++ de telle manière que les utilisateurs de la classe ne doivent pas nécessairement recompiler leurs programmes chaque fois que ma mise en œuvre de la classe change" est le modèle PIMPL. Pour plus d'informations: http://en.wikipedia.org/wiki/opaque_pointer


2 commentaires

Les itérateurs C ++ sont copieux. Les pointeurs ne fournissent pas la sémantique nécessaire pour cela. Notez également que le type d'itérateur concret est inconnu un code utilisateur. Cela rend pimplacplicable pimplacplicable ici.


Vous devez juste 1. envelopper vos itérateurs de la même manière (YEP, également à l'aide de PIMPL), 2. Implémentez votre opération de copie non-triviale (bien qu'elle soit plutôt triviale dans sa non-provisoire).



0
votes

Je comprends complètement la question de l'utilisateur. Il / elle veut une classe de conteneurs personnalisée qui expose à l'utilisateur une interface de type STL. Les conteneurs STL standard ne suffisent pas d'une certaine manière et ils ne sont donc pas un choix approprié.

Par exemple, j'ai une classe d'interface pour une «Dataline» appelée idataline. Une implémentation de l'interface IDataline prend à la construction d'une chaîne délimitée, analyse et expose la liste des champs. Via un const_iterator avec la sémantique Forward_iterator_Tag. Aucun conteneur STL ne peut le faire hors de la boîte.

En outre, ma classe client souhaite pouvoir parcourir deux champs de lignes de données et les comparer, le champ par champ.

J'ai défini l'interface IDataline comme suit: xxx

Le problème est vu sur les lignes 11, 18 et 19 - Nous devons pouvoir être capables de Renvoyer un const_itéator, qui nécessite un constructeur de copie, mais comme il est virtuel, il n'y a ni de par défaut ni un constructeur de copie (pour le type d'interface) et le compilateur (correctement).

Vous pourriez argumenter que Je pourrais définir le début () et la fin () comme: xxx

alors, je peux créer deux instances de l'itérateur spécialisé dans l'hôte spécialisé et renvoyer des références (ou des pointeurs pour ceux-ci qui préfèrent ceux-ci), pour que cela fonctionne pour travailler pour mon cas.

Le problème est qu'une telle mise en œuvre ne répond pas à toutes les exigences des itérateurs transfrontaliers et se cassera dans des cas d'utilisation plus générale qui s'appuient sur l'itérateur à terme Sémantique.

Il y a deux façons que j'ai trouvé après un peu de pensée (et de collègue consultez) que cela peut être adressé:

  1. Votre classe hôte doit-elle être complètement résumé? Si vous pouvez minimiser l'abstraction vers le comportement que vous devez varier, votre hôte instansible peut incorporer un itérateur en béton (car une instance de la classe elle-même peut être instanciée) et vous avez ce dont vous avez besoin.

  2. Eduardo Leon ci-dessus indique que l'itérateur lui-même peut être enveloppé à l'aide du pimpl (pointeur à une implémentation) idiome. Bien qu'il y ait beaucoup de matériel disponible qui décrit minutieusement cette technique, basilev , dans les commentaires ci-dessous Suggestion de Leon, indique qu'il ne croit pas que l'idiome PIMPL fonctionnera. Mon collègue m'a offert une technique à essayer, alors je vais élaborer un échantillon testé. Si cela fonctionne, je le partagerai. Sinon, je détaillerai l'expérience acquise dans l'échantillon et attendrai que quelqu'un de plus connu pour peser sur si Pimpl est applicable ou non dans ce cas.


0 commentaires

2
votes

2 commentaires

+1 Pour le type de mention Erasure et le travail de Becker - Any_berator est probablement la solution parfaite ici. Aucune idée de la raison pour laquelle vous mentionnez Ecary Tho, je pensais que c'était principalement sur la suppression de la dépendance des allocator à partir d'itérateurs (qui n'a rien à voir avec des interfaces génériques, mais mettant en œuvre l'itérateur sur le même «niveau» que le conteneur et non comme une classe imbriquée IIRC ).


Scary, bien sûr, est un détail de mise en œuvre et, comme vous l'avez dit, c'est orthogonal. J'ai ajouté que la peine plus tard, lorsque je me suis rendu compte, cela pourrait potentiellement mettre en œuvre et expérimenter les nouveaux itérateurs un peu plus agréable.