() et types variants [C++/résolu] operator [][] - C++ - Programmation
Marsh Posté le 18-03-2006 à 18:03:04
tu surcharges operator[] et tu lui fait retourné un objet pour lequel tu peut appliquer []
dans le cas d'une matrice l'appel du premier [] retourne l'adresse de la ligne sur laquel on peut indexer la colonne voulue
Code :
|
mais bon, ca existe deja
Marsh Posté le 18-03-2006 à 18:27:45
skelter> merci
>mais bon, ca existe deja
En fait j ai un cas pratique, dans lequel j ai des classes polymorphes, auquelles il serait utile de fournir cet opérateur, mais les classes ont des tableaux différents en taille, en type, en nombre de dimensions. Parfois elles n ont pas du tout de tableaux (dans ce cas l opérateur renvoie une constante).
Marsh Posté le 19-03-2006 à 04:04:27
Bon, apparemment y a pas de solution simple.
Ça va être:
virtual const Val& get(uint, uint) const;
et:
virtual void set(uint, uint, const Val& );
à la bonne franquette!
Marsh Posté le 19-03-2006 à 10:07:32
ReplyMarsh Posté le 19-03-2006 à 10:19:10
haha, merci du conseil taz, mais je me suis fait mon propre autoptr et autoarray. Comme je le disais, ça va être à la bonne fanquette: programmé avec les doigts!
Marsh Posté le 19-03-2006 à 11:51:09
Taz a écrit : et pitié, au minimum mettez des vector<> derrière |
oui, ou valarray
Citation : |
ca marche ce que je t'ai montré et c'est simple
get/set c'est nul à utiliser (surtout le set avec la valeur en 3e parametre), tu pourrais également surcharger operator(), ca se fait aussi
Marsh Posté le 19-03-2006 à 12:31:59
> sans doute complètement pourri donc ...
non...!? j ai pas l impression d avoir besoin de vector. juste d allouer des blocs de mémoire partagés et détachables. j ai même pas d objets là dedans, c est des images.
les blocs mémoire peuvent par ailleurs être gérés par le hardware ou partagés en réseau.
je ne me sent pas assez confortable avec std:: pour trouver les bonnes classes pour faire ça.
> oui, ou valarray
ça peut être interessant
> get/set c'est nul à utiliser
ouais!
> surcharger operator()
bonne idée!
Marsh Posté le 19-03-2006 à 14:11:47
Citation : non...!? j ai pas l impression d avoir besoin de vector. juste d allouer des blocs de mémoire partagés et détachables. j ai même pas d objets là dedans, c est des images. |
essaies quand meme avec std::vector ou autre et montre le code si il y a un probleme
Marsh Posté le 19-03-2006 à 15:41:24
C est possible de faire travailler std::vector sur de la mémoire déjà allouée via mmap()?
Marsh Posté le 19-03-2006 à 15:48:28
std::vector est parametrable au niveau de l'allocateur, ca permet pas mal de chose
mais je comprends pas pourquoi tu voudrais que ton vector utilises de la mémoire allouée par mmap, ca n'a pas de sens ? tu veux faire quoi ?
Marsh Posté le 19-03-2006 à 16:14:49
Le but, c est d arriver à faire dériver plusieurs classes de façon à pouvoir plugger entre eux des flux vidéos. Des flux vidéo sources:
- webcam (mmap)
- tv in (mmap mjpeg temps réel)
- fichier vidéo (décompression en mémoire),
des flux cibles:
- librairie graphique (soft)
- buffer carte vidéo (hard)
- overlay carte vidéo (hard)
- carte compression vidéo (hard)
- tv out (hard)
- fichier vidéo (soft)
Pour l instant, je me suis dit que pour factoriser au maximum les classes polymorphes, j aurai besoin d un gestion mémoire particulière qui puisse à la fois gérer un flux vidéo hardware en provenance d une webcam (souvent mmap) ou à destination d une carte video (buffer video), et avoir possibilité de détacher ou partager ces tampons mémoire pour des filtres software (resize notamment).
Marsh Posté le 19-03-2006 à 23:11:43
Taz avait présenté une solution exploitant un proxy dans une autre file. Ca s'applique ici aussi.
Marsh Posté le 20-03-2006 à 14:18:27
http://forum.hardware.fr/hardwaref [...] 0942-1.htm
ouah je suis bon moi je m'en souvenais même plus.
Marsh Posté le 20-03-2006 à 20:02:17
Salut les génies
Bon, alors je me suis décidé pour utiliser l opérateur () (uint,uint), histoire d éviter à avoir à coder deux fois plus de classes polymorphes.
Pour std::vector, j ai étudié le doc publié par gnu gcc, très instructif les allocators. Mais je vais essayer de le placer là où il faut.
J ai d autres problèmes:
1°) mon compilateur préféré (gcc) aligne mes classes sur des mots: 1, 2 ou 4 octets, ce qui n est pas du tout du goût de ma webcam qui utilise une array de 3 octets par pixels.
2°) je suis un peu perdu dans les variants (il me semble que ça s appelle comme ça).
J encapsule les différents formats de pixels (ex: class GRAY/RGBA) dans une classe abstraite Signal pour pouvoir faire:
cartevideo(x,y)=webcam(x,y);
(rem: ça doit pas être trop optimisé tout ça)
un peu de code:
Code :
|
> Signal& operator () (unsigned int, unsigned int)
> { return SignalGRAY(_color); }
Ça c est une grosse connerie:
Code :
|
J ai comme l impression que je fait fausse route, non?
Marsh Posté le 20-03-2006 à 20:30:02
nargy a écrit :
|
N-ième fois : Assigner un temporaire à une référence non const, c'est illégal.
Assigner un temporaire à une référence constante, c'est légal mais *dans ton cas* stupide car le temporaire va cesser de vivre à la fin de sa scope.
Marsh Posté le 20-03-2006 à 20:44:43
oui, j ai bien précisé:
> Ça c est une grosse connerie:
Seulement si je fait:
> Signal operator () (unsigned int, unsigned int)
> { return SignalGRAY(_color); }
c en est une autre: ma classe Signal possède des fonctions virtuelles pures.
je sèche sur la solution...
Marsh Posté le 20-03-2006 à 21:29:19
ha oauis, je fait fausse route, les variants se font avec des templates. je sens que ça va se terminer avec un gros switch ou une array de pointeurs de fonctions.
Marsh Posté le 20-03-2006 à 22:19:26
#
virtual Signal& operator=(RGBA)=0;
#
virtual Signal& operator=(GRAY)=0;
#
virtual operator RGBA () const =0;
#
virtual operator GRAY () const =0;
tu crois faire quoi là ?
Marsh Posté le 20-03-2006 à 23:11:18
Enfin, ce sont des fonctions viruelle pures, réimplémentées dans SignalGRAY, par ex..
Ainsi, quand j ai une classe qui dérive de Signal, je peut convertir la valeur représenté de et vers n importe quelle autre palette.
Puis je pensais utiliser celà pour écrire:
cartevideo(x,y)=webcam(x,y);
Mais je me rends compte que pour utiliser les fonctions virtuelles, je dois à un moment donné avoir un pointeur (ou une ref) sur l objet signal.
Marsh Posté le 20-03-2006 à 23:22:54
ha ouais j ai pigé ce que tu voulais dire:
> tu crois faire quoi là ?
- j initialise un objet signal en mettant ces fonctions à nul.
Pour utiliser cette méthode, j en suis à <<où trouver un pointeur sur l objet SignalGray?>>
Je peut toujours le créer avec un new ou un delete, mais ça implique une allocation mémoire à gérer, et ça commence à faire beaucoup de pointeurs.edit:
edit:
j ai un peu googlé et je n ai trouvé que deux moyens de faire des objets ``variant``:
- un gros switch pabo,
- des templates qui se résolvent à la compilation.
Marsh Posté le 21-03-2006 à 11:43:20
>
c est une blague, ou le sujet t interesse?
j ai renommé ma classe signal en basesignal, et j ai maintenant une classe signal qui contient un pointeur sur un new basesignal et des constructeurs/destructeurs & opérateurs =. ça compile, mais j ai pas encore testé. je le sens pas.
je teste demain, si ça marche, je publie un code propre.
> je peut toujours le créer avec un new ou un delete, mais ça implique une allocation mémoire à gérer, et ça commence à faire beaucoup de pointeurs.
- utiliser un pool? std::__pool_allocator?
Marsh Posté le 21-03-2006 à 18:23:06
<Note>
Je cherche à connecter dans un premier temps 1 webcam, 1 carte tv-in, mixer le tout et envoyer le résultat sur 1 carte video-overlay et 1 carte vidéo-buffer via réseau. Je ne connais pas à l avance les palettes de couleur, les tailles et le fps des entrées-sorties vidéo. Chaque périphérique a sa gestion propre de son espace mémoire (sauf le réseau où j ai le choix).
</Note>
Ok, j ai élagé un max le code.
Normalement, je gère dans des fichiers à part les définitions/conversions de couleurs. J ai aussi un fichier pour les types qui dépendent du CPU (tailles/endienness).
Dans ce morceau je n ai gardé que 2 types de palettes graphiques: RGBA (4 channels=32bits), GRAY (1 channel=8bits), et un type NumericSignal (1 channel=flottant) (pour tester).
Mes ulucubrations de vocabulaire:
Signal = pixel,
Plot = réseau, mémoire ou périphérique vidéo.
Code :
|
Ok, et ça marche :
Code :
|
Reste à faire quelques tests de rapidité, puis reproduire la méthode pour les périphériques pour pouvoir écrire directement quelquechose comme:
Code :
|
Marsh Posté le 22-03-2006 à 11:58:26
> utiliser un pool? std::__pool_allocator?
Avec du debug sur les allocations du test précédent:
Code :
|
indique qu une pile est plus apropriée.
Marsh Posté le 22-03-2006 à 14:36:59
> J ai comme l impression que je fait fausse route, non?
oui: total space cette méthode de classe de variants avec fonctions virtuelles
j ai recodé en utilisant un tableau statique à deux dimensions avec des pointeurs sur les fonctions de convertion et une classe signal contenant:
void* pval;
unsigned int mytype;
Signal& operator=(const Signal& o)
{
(conversions[mytype][o.mytype])(pval,o.pval);
return *this;
}
au lieu d un pointeur sur BaseSignal,
comparaison sur 30 millions d affectations: edit:
Code :
|
C est pas très joli les void*, et c est presque plus du C++, mais il y a un facteur 2,6 à 5,2.
Marsh Posté le 22-03-2006 à 19:44:24
nargy a écrit : oui: total space cette méthode de classe de variants avec fonctions virtuelles |
Comme tu dis. ça ne correspond en rien avec ce que j'ai l'habitude non seulement d'écrire, mais de voir. Déjà, variant, je ne sais pas d'où tu sors ce terme, mais je n'ai pas l'impression que tu te référes aux variants (à la Alexandrescu) que la littérature évoque -- et que Boost.Variant implémente, notament.
Après, j'ai du mal avec l'opertor= virtuel ...
Vu que tu as des conversion à faire, j'aurai utiliser les constructeurs pour convertir dans un sens, et les Proxy pour convertir dans l'autre sens.
Citation : j ai recodé en utilisant un tableau statique à deux dimensions avec des pointeurs sur les fonctions de convertion et une classe signal contenant: |
Je ne comprends pas tout ce que tu essayes de faire, mais pour éviter le void*, et faire des conversions efficaces, quelquechose dans cet esprit doit pouvoir marcher :
Code :
|
Citation : comparaison sur 30 millions d affectations: edit:
|
Est-ce que ce test reflète parfaitement l'utilisation que tu en as ? Est-ce qu'un profiler ne serait pas plus précis pour mesurer les performances de ce code dans le contexte de ton application ?
Citation : C est pas très joli les void*, et c est presque plus du C++ |
Ah
Marsh Posté le 22-03-2006 à 19:46:18
ReplyMarsh Posté le 22-03-2006 à 21:18:46
++fab> merci de tees comments
> variant
- ouais, c est pas tout à fait ça, ça y ressemble vaguement, dans le sens où c est une classe qui est une union de plusieurs types.
> Après, j'ai du mal avec l'opertor= virtuel
- j en avais peut être pas besoin d ailleurs du virtuel
> pour éviter le void*, et faire des conversions efficaces, quelquechose dans cet esprit doit pouvoir marcher ...
- ouais la version template c est à peu ça, pour N types à convertir entre eux, il y a N*N fonctions de conversions (N=33).
> Est-ce que ce test reflète parfaitement l'utilisation que tu en as ?
- non, c est dans le pire des cas.
> C est pas très joli les void*, et c est presque plus du C++
- ...mais du C
> indique qu une pile est plus apropriée.
- parceque les allocations/désallocations de Signal ne se croisent pas (même si elles se croisaient la pile resterait dans des limites raisonnables), et une pile est ce qu il y a de plus rapide.
> Je ne comprends pas tout ce que tu essayes de faire
Ce que j essaye de faire: relier des périphériques vidéos.
Pour prendre un schema très simple: afficher la vidéo d une webcam sur un écran.
La webcam est gérée avec video4linux. Video4linux me donne un pointeur sur une zone mémoire contenant l image courante. Video4linux m informe aussi du codage de couleurs: Gray8 ou Bgr24.
Pour faire simple, l écran est géré par le serveur X. Le serveur me donne un pointeur vers la mémoire vidéo et m informe de la palette utilisée: Rgb24 ou Rgb32.
La webcam et l écran peuvent changer de palette, j ai donc besoin de fonctions de conversions de palette de la forme:
convertir(adressevideo* dest, adressevideo* source);
... pour toutes les combinaisons de palettes necessaires.
J ai déjà écrit un programme d affichage de webcam en C avec de gros switch et une interface C++, résultat: c est lent (sauts de frames) et pas pratique à réutiliser/modifier.
J ai divers morceaux de code pour faire pareil avec ma carte télé et une carte vidéo overlay. J ai plusieurs filtres vidéo aussi: écran bleu, détecteur de mouvement.
Je cherche à réunir ces morceaux de codes de façon homogène et réutilisable simplement, comme par exemple:
ecran(x,y)=webcam(x,y);
...sans se soucier des palettes à l extérieur des objets ``ecran`` et ``webcam``.
Marsh Posté le 22-03-2006 à 21:32:35
ha oui:
> convertir(adressevideo* dest, adressevideo* source);
> ... pour toutes les combinaisons de palettes necessaires.
D où mon idée de faire un tableau de N*N cases avec les fonctions de conversion dedans.
D où ces étranges lignes de code:
void* pval;
unsigned int mytype;
Signal& operator=(const Signal& o)
{
(conversions[mytype][o.mytype])(pval,o.pval);
return *this;
}
Marsh Posté le 22-03-2006 à 22:00:39
Citation : > variant |
L'implémentation d'un variant est tellement traumatisante, que ton code aurait du m'y faire penser
Citation : > Après, j'ai du mal avec l'opertor= virtuel |
Considère la solution Proxy pour émuler la surcharge du type de retour, et constructeur multiple peut-etre ?
Citation : > pour éviter le void*, et faire des conversions efficaces, quelquechose dans cet esprit doit pouvoir marcher ... |
Et comment tu regle ce coup avec ton tableau de pointeur de fonction ?
Citation : > C est pas très joli les void*, et c est presque plus du C++ |
Ma remarque n'allait pas dans ce sens ...
Citation : > indique qu une pile est plus apropriée. |
Rien compris. Je n'arrive pas à comprendre comment tu peux présupposer du comportement de l'allocateur standard.
Mais si tu as le choix, et qu'une classe de stockage automatique fait l'affaire (C++ ne connait pas la pile), ne t'en prives pas.
Citation : Je cherche à réunir ces morceaux de codes de façon homogène et réutilisable simplement, comme par exemple: |
J'arrive pas à saisir la sémantique de ton operator=. ça veut dire "Chaque pixel de la webcam se retrouve sur l'écran" ?
Ce ne serait pas plus élégant de l'exprimer comme ça :
Code :
|
Marsh Posté le 22-03-2006 à 23:28:27
> Et comment tu regle ce coup avec ton tableau de pointeur de fonction ?
un peu de code, ça sera plus simple:
Code :
|
> ça veut dire "Chaque pixel de la télé se retrouve sur l'écran" ?
- juste le pixel situé à la position (x,y)
Code :
|
Oui, ça c est pour gérer le niveau flux vidéo. Mais avant d en arriver là, je doit gérer le niveau pixel: palettes de couleurs variables.
Après il y a le niveau image: tailles variables.
Enfin le niveau du flux vidéo: fps différents et entrelacements différents.
Dans l idéal, j ai des fonctions de conversion spécialisée vers tous les types possibles de périphériques avec toutes les tailles et tous les formats de pixel. Mais avant d en arriver là:
Code :
|
...la copie pixel par pixel est obligatoire.
Marsh Posté le 23-03-2006 à 00:24:55
Je vois 2 autres techniques :
1 - modèle stratégie
Code :
|
2- classe template
Code :
|
avec Converter comme décrit plus haut.
1- est souple à l'exécution.
2- n'est souple qu'à la compilation, mais est plus efficace. La, tu peux t'attendre à ce que le compilateur développe en ligne tout les appels.
Marsh Posté le 23-03-2006 à 01:07:45
Ha oui, je te suis. Mais, il y a un gros mais...
D abord en ce qui concerne la méthode 2, les templates se résolvent à la compilation, or il est tout à fait possible que le format de pixel change pendant l execution. Par exemple, en utilisant xrandr sur le serveur X.
Ensuite pour la méthode 2:
J'ai testé deux programmes, l'un avec des fonctions virtuelles, l'autre avec des pointeurs sur fonction.
Les pointeurs sur fonction sont 2 fois plus rapides. J'ai trouvé l'explication suivante:
objet -> vtable -> pfonction -> code
ça fait minimum 3 déréférences pour appeler une fonction virutelle, et:
objet -> pfonction -> code
donc minimum 2 déréférences avec les pointeurs sur fonction, or en assembleur i586+:
C = nbre cycles pour 1 déréférence = nbre cycles pour 2 déréférences
donc:
nbre cycles 3 déréférences = 2*C
=> les fonctions virtuelle sont au moins deux fois plus lentes que des pointeurs sur fonction.
Quand je fait:
Code :
|
j utilise 1 déférence pour le tableau, 1 pour le pointeur de fonction. L opérateur = lui même est en inline.
La méthode que j ai exposé plus haut ressemble à la tienne, à celà près que je mettais la classe SignalType en sous classe de Signal. Sinon du point de vue performances c est la même chose, le code assembleur doit être très proche sinon identique.
Je peut envisager la méthode 1 pour le niveau image, ou flux vidéo. Pour le niveau pixel je suis obligé de privilégier la performance. Pour une image 1MégaPixel les fonctions virtuelle me limitent à 8 fps et avec pointeur sur fonction 30 fps.
Ok, je te remercie, il me semble avoir fait le tour des méthodes pour avoir disons des classes convertibles entre elles.
Je vais me mettre la méthode des templates sous le coude pour les flux vidéo avec palette fixe.
Si tu aimes te prendre la tête sur les templates récursifs, une implémentation de variant que j ai étudié (j ai pas encore tout pigé...):
http://www.codeproject.com/cpp/union_list.asp
Marsh Posté le 23-03-2006 à 01:10:47
la difference entre une fonction virtuelle et un pointeur de fonction m'echappe pas mal
Marsh Posté le 23-03-2006 à 01:19:04
elles te permettent toutes les deux d effectuer un code différent en fonction d un type d objet, à l execution.
Marsh Posté le 18-03-2006 à 17:32:21
Salut les C++iens!
Alors voilà, je me demandais quelle méthode utiliser en C++ pour surcharger l'opérateur [][]: oui vous ne voyez pas double , il ne s'agit pas de [] mais de [][].
Quelque chose comme:
Tableau2D tab(10,10);
tab[2][1]=0;
Y a t-il une solution efficace?
solution 1 => un proxy: sucharger[] retourner un objet avec [] surchargé
solution 2 => surcharger plutôt operator()
Deuxièmement:
Comment faire retourner à l'opérateur un objet variant de plusieurs types convertissables entre eux? (variant ~=~ union)
* Solutions résolvables à la compilation:
solution 1 => utiliser un template, et l'instancier avec toutes les conversions possibles. mots clés: Boost.Variant+Alexandrescu
solution 2 => plus facile à coder, plus lent: avoir un type de plus grande précision utilisé pour convertir de/vers les autres type. ex.: type string.
* Solutions complémentaires, résolvables à l'execution:
solution 1 => pour un nombre restreint de types variants: un switch,
solution 2 => pur C++, pour de gros objets: une classe conteneur d'un pointeur vers une classe abstraite pure. mots-clés ci-dessous: ++fab+SignalType
solution 3 => plus efficace sur des petits objets: une classe faisant appel à un tableau statique à 2 dimensions de pointeurs sur fonctions de conversion. mots clés ci-dessous: conversions+mytype
Message édité par nargy le 24-03-2006 à 00:04:25