J'ai une base de code importante, à l'origine C porté à C ++ il y a de nombreuses années, qui fonctionne sur un certain nombre de grandes matrices de données spatiales. Ces tableaux contiennent des structures représentant des entités de point et de triangle représentant des modèles de surface. J'ai besoin de refactoriser le code de telle sorte que la manière dont ces entités soient stockées varie en interne varie en interne pour des scénarios spécifiques. Par exemple, si les points se trouvent sur une grille plate régulière, je n'ai pas besoin de stocker les coordonnées X et Y, car ils peuvent être calculés à la volée, comme cela peut les triangles. De même, je souhaite profiter des outils de base tels que STXXL pour stockage. Le moyen le plus simple de le faire consiste à remplacer l'accès au tableau avec des fonctions de type et d'obtention de type, par exemple
point[a].z = point[b].z + point[c].z
4 Réponses :
Vous n'avez pas besoin de passer la matrice par valeur. Pour la mutation des valeurs de la matrice, vous voulez deux versions de Il n'y a aucune raison de principe de ne pas utiliser Regardant votre code d'échantillon, il a un test de stratégie de stockage. Ne faites pas cela. Utilisez OO et demandez à votre objet de stockage implémenter une interface virtuelle commune, ou (probablement mieux) utilisez la programmation de modèle pour faire varier le mécanisme de stockage. P>
Si vous regardez les garanties fabriquées par opérateur [] code>, qui renvoie une référence (à la mutate) et une référence Const. p>
opérateur [] code>, tant que vous n'avez pas besoin de modifier le type de stockage au moment de l'exécution - il n'y a pas d'opérateurs virtuels, de sorte que vous le feriez. Besoin d'une fonction nommée si vous souhaitez polymorphisme d'exécution. Dans ce cas, vous pouvez créer un simple
struct code> qui adapte les appels de l'opérateur aux appels de fonction (bien qu'il dépend plutôt de l'API de stockage - si le code suppose que l'attribution aux variables de membre du point change les données stockées. , vous devrez peut-être apporter le point de taper une variable de modèle aussi pour que cela puisse être remplacé). P>
std :: vecteur code> (dans des normes C ++ plus récentes), il est possible d'avoir quelque chose qui a un stockage dynamique et permet une utilisation de l'arithmétique du pointeur, bien que cela nécessite un stockage contigu. Étant donné que certaines de vos valeurs sont créées à la volée, il ne vaut probablement pas la peine de placer cette restriction sur vos implémentations, mais la contrainte elle-même n'empêche pas l'utilisation de
opérateur [] code>. p>
Le retour d'une référence au point implique d'avoir plusieurs points uniques pour toutes les références potentiellement en direct actives en même temps. Cela nécessitera une cache de données transformées, mais devrait être fonctionnel. Merci d'avoir répondu.
Utilisation du WRT d'une stratégie de stockage plutôt que de OO ou de modèles, cela ne fonctionnerait pas car le code existant n'est pas écrit pour le soutenir et une exigence principale est de minimiser la quantité de réécriture. Je veux laisser tomber quelque chose qui est polymorphe polymorphe à l'arrière, mais à l'extrémité frontale imite une matrice C. Si je l'écrivais à partir de zéro, les modèles sont sans aucun doute la voie à suivre.
Ce que vous voulez est possible, mais comme vous avez besoin d'un accès en écriture également, le résultat sera parfois un peu plus complexe. Ce que vous voulez, c'est la fonction Setter renvoyant non pas un "accès en écriture de points", plutôt une copie temporaire, qui fera l'écriture une fois que la copie sort de la portée.
Le fragment de code suivant tente de décrire la solution: P>
class PointVector { MyClass container_; public: class PointExSet: public Point { MyClass &container_; int index_; public: PointExSet(MyClass &container, int index) :Point(container.GetVector(index)),container_(container),index_(index) { } ~PointExSet() { container_.PutVector(index_) = *this; } }; PointExSet operator [] (int i) { return PointExSet(container_,i); } };
Yup, d'où la nécessité de références. Je pense que je devrais pouvoir le faire en utilisant une cache du type transformé, avec un index de la même taille que le tableau utilisé pour maintenir le cache.
Pour avoir un contrôle total sur les opérations sur le tableau, l'opérateur [] doit renvoyer un objet spécial (inventé il y a longtemps et appelé "curseur") qui gérera les opérations pour vous.
À titre d'exemple:
Après avoir lu les réponses ci-dessus, j'ai décidé que la réponse de Pete avec deux versions de Le stockage de données principale est dans excuses à tous vos fans de tous vos fans l'aperçu des MFC plus âgés; Le reste du projet est MFC, il a donc plus de sens dans ce cas. Le cbigarray était le résultat d'un question de dépassement de pile associée qui est devenue la base de ma grande manipulation de la matrice. J'espère terminer la mise en œuvre aujourd'hui et tester demain. Si tout va du ventre sur moi, je modifierai ce post avec précision. P> p> opérateur [] code> était la meilleure voie à suivre. Pour gérer le morphing entre les types au moment de l'exécution, j'ai créé une nouvelle classe de modèles de tableau qui a pris quatre paramètres comme suit;
m_basedata code> qui Est-ce que les données de son format natif, qui peuvent varier en type comme indiqué.
m_refcache code> est une matrice secondaire au cache des éléments dans le format attendu, et la fonction
getcachedelement code> utilise les fonctions virtuelles
convertissez code> pour traduire les données telles que c'est déplacé dans et hors du cache. Le cache doit être au moins aussi gros que le nombre de références simultanées pouvant être actives à une fois, mais dans mon cas bénéficiera probablement d'être plus grande, car elle réduit le nombre de conversions requises. Alors que la mise en œuvre du curseur d'ALSK aurait probablement bien fonctionné, la solution donnée nécessite moins de copies d'objet et de variables temporaires, et devrait donner une légère meilleure performance qui est importante dans ce cas. P>