Accueil Ti-Gen Foire Aux Questions Chat sur le chan #tigcc sur IRC
Liste des membres Rechercher Aide
Bienvenue Invité !   Se connecter             Mes sujets   
Administrer
0 membre(s) et 1 visiteur(s) actif(s) durant les 5 dernières minutes Utilisateurs actifs : Aucun membre + 1 visiteur
Avant de poster sur le forum, il y a des régles de bases à respecter pour une bonne entente et un respect de tous.
Veuillez lire la charte du forum.
  :: Index » Forum Ti68K » Programmation C » Orienté objet avec TIGCC (113 réponse(s))
./REPRISE DU POST PRECEDENT (post n°57)   Marquer comme non lu.
Quésoft Ecrit le: Vendredi 20 octobre 2006 à 19:58 Déconnecté(e)    Voir le profil de Quésoft Envoyer un email à Quésoft Visiter le site WEB de Quésoft Envoyer un message privé à Quésoft  

ah oui, question technique assez critique:

Pour les objets locaux, même en connaissant tout le contexte, comment déterminer statiquement qu'un objet local devra être finalisé dans ce genre de cas:


void a() {
  auto Object_featuring_finalization o;

  b();
}

void b() {
  exit();
}


Je ne vois pas quoi faire d'autre que ce que fait Moka (décrit plus haut)...
    
./Post n°58   Marquer comme non lu.
Pollux Ecrit le: Vendredi 20 octobre 2006 à 20:01 Déconnecté(e)    Voir le profil de Pollux Envoyer un email à Pollux Envoyer un message privé à Pollux  

Quésoft :
1. Les fichiers sources
Le préprocesseur va garder intact le formatage du fichier source et ne touchera qu'aux déclaration de classe et aux mécanismes OO qu'il devra convertir dans les fonctions.

Ce serait quoi l'intérêt en fait ? mélanger du code C et du code mokalite ? #confus#


Quésoft :
ah oui, question technique assez critique:

Pour les objets locaux, même en connaissant tout le contexte, comment déterminer statiquement qu'un objet local devra être finalisé dans ce genre de cas:


void a() {
  auto Object_featuring_finalization o;

  b();
}

void b() {
  exit();
}


Je ne vois pas quoi faire d'autre que ce que fait Moka (décrit plus haut)...

Pour les constructeurs, c'est facile: on passe l'objet local par adresse juste en dessous de la déclaration (s'il y a un constructeur pour cet objet). Par contre, les destructeurs, c'est plus difficile. Moka plaçait les objets locaux dans un vecteur. Ainsi, si le programme était quitté sans quitter le scope où avait été déclaré l'objet, il était finalizé par une boucle dans une fonction atexit. Cette solution a le désavantage d'augmenter sensiblement la taille du programme, alors je me demandais si vous avez des solutions plus efficaces. La solution la plus simple reste bien sur de ne pas permetre les classes ayant un destructeurs d'être utilisées localement, mais ça fait perdre les objets locaux de leur charme.

cf mon post précédent :) (et à mon avis ce serait bcp trop prise de tête si seules les classes sans destructeurs pouvaient être utilisées)
    
./Post n°59   Marquer comme non lu.
Kevin Kofler Ecrit le: Vendredi 20 octobre 2006 à 20:31 Déconnecté(e)    Voir le profil de Kevin Kofler Envoyer un email à Kevin Kofler Visiter le site WEB de Kevin Kofler Envoyer un message privé à Kevin Kofler  


Pollux :
Non, ce n'est pas de ça que je parle : ton truc revient plus ou moins en C ansi à faire des setjmp/longjmp, et c'est évidemment très coûteux en temps et en taille si on s'amuse à faire ça à chaque déclaration d'une nouvelle variable... En plus comme tu dis ça pose des pbs avec l'allocation de registres.
Ce qu'il faudrait, c'est qu'en examinant le program counter ou la pile, on ait des métadonnées qui permettent de déterminer quelles sont les variables locales à détruire pour sortir proprement de la fonction ^^

Donc tu veux de l'unwinding info DWARF 2. ;) Faut un frontend GCC pour ça...

Non, c'est pas suffisant, parce que par exemple pour les chaînes il faut stocker le contenu dans une zone malloc()ée... Idem pour les tableaux et tout ça ^^

alloca :) VLAs C99 aussi. :) Bien sûr, faut inliner les opérations sur les chaînes de caractères et les vectors pour faire ça.
-Edité le Vendredi 20 octobre 2006 à 20:33 par Kevin Kofler-
Membre de l'équipe de TIGCC: http://tigcc.ticalc.org
Mainteneur du portage Linux/Unix de TIGCC: http://tigcc.ticalc.org/linux/
Membre de l'équipe de CalcForge: http://www.calcforge.org:70/

Participez à la reprise de Ti-Gen!
    
./Post n°60   Marquer comme non lu.
Quésoft Ecrit le: Vendredi 20 octobre 2006 à 22:52 Déconnecté(e)    Voir le profil de Quésoft Envoyer un email à Quésoft Visiter le site WEB de Quésoft Envoyer un message privé à Quésoft  

Pollux :
Ce serait quoi l'intérêt en fait ? mélanger du code C et du code mokalite ? #confus#


Moka fait déjà de l'interopérabilité avec le C (genre native.printf("toto"); ou native {char *str = malloc(4);})

C'est plutôt parce que ce préprocesseur ne fera qu'ajouter le support des classes en C (et d'autres goodies en temps et lieu).

Pollux :
cf mon post précédent :)


Les métadatas ? Ce serait une solution élégante pour un compilateur qui génère du natif, mais pour générer ça en C, ça revient un peu comme la solution de Moka en terme d'overhead (mémoire ou temps de traitement), non ? Et c'est d'une complexité plus élevée.

Pollux :
(et à mon avis ce serait bcp trop prise de tête si seules les classes sans destructeurs pouvaient être utilisées)


Ce serait très désolant, en effet...

Il n'y a pas d'autres solutions ? Si c'est le cas, je vais sticker avec la solution Moka: si l'objet n'a pas de destructeur, tant mieux. Sinon, je l'ajoute à une liste des objets locaux présentement alloués (et je le retire lors de la sortie du scope) et je fais une atexit qui fait le ménage en cas de fin abrupte.
    
./Post n°61   Marquer comme non lu.
Pollux Ecrit le: Vendredi 20 octobre 2006 à 23:17 Déconnecté(e)    Voir le profil de Pollux Envoyer un email à Pollux Envoyer un message privé à Pollux  

Quésoft :
Pollux :
cf mon post précédent :)


Les métadatas ? Ce serait une solution élégante pour un compilateur qui génère du natif, mais pour générer ça en C, ça revient un peu comme la solution de Moka en terme d'overhead (mémoire ou temps de traitement), non ? Et c'est d'une complexité plus élevée.

Non, les métadonnées c'est si le compilo les supporte (sinon évidemment il y a un overhead et ça sert plus à rien), mais sinon la méthode du scan de la pile devrait pas trop mal marcher et apporter de gros gains de place et de vitesse :) (et en fait tu peux même te débrouiller pour pas avoir besoin de stack frame du tout)
    
./Post n°62   Marquer comme non lu.
Jfg Ecrit le: Vendredi 20 octobre 2006 à 23:34 Déconnecté(e)    Voir le profil de Jfg Envoyer un email à Jfg Visiter le site WEB de Jfg Envoyer un message privé à Jfg  


les specs que je préfèrerais:
-pour les constructeurs, faire comme en java
-utiliser une extension spécial (ni .c ni .java) pour les fichiers sources
-avoir que des classes publiques
Kill Mario
    
./Post n°63   Marquer comme non lu.
Quésoft Ecrit le: Samedi 21 octobre 2006 à 00:10 Déconnecté(e)    Voir le profil de Quésoft Envoyer un email à Quésoft Visiter le site WEB de Quésoft Envoyer un message privé à Quésoft  

Jfg :
les specs que je préfèrerais:
-pour les constructeurs, faire comme en java
-utiliser une extension spécial (ni .c ni .java) pour les fichiers sources
-avoir que des classes publiques


Merci pour ces réponses. Moi aussi j'aime bien la sémantique java. Pour le .java, l'avantage est que les éditeur utilisent la bonne coloration syntaxique automatiquement, sans avoir à toucher à quoi que ce soit.

Par curiosité, pour les classes protected et private, qu'est-ce qui vous déplais ?
    
./Post n°64   Marquer comme non lu.
Quésoft Ecrit le: Samedi 21 octobre 2006 à 00:15 Déconnecté(e)    Voir le profil de Quésoft Envoyer un email à Quésoft Visiter le site WEB de Quésoft Envoyer un message privé à Quésoft  

Pollux :
Non, les métadonnées c'est si le compilo les supporte (sinon évidemment il y a un overhead et ça sert plus à rien), mais sinon la méthode du scan de la pile devrait pas trop mal marcher et apporter de gros gains de place et de vitesse :) (et en fait tu peux même te débrouiller pour pas avoir besoin de stack frame du tout)


Autres choses... Il faut quand même une méthode 'atexit', non ? Pour trouver les objets sur la pile, on fait quoi ? On stack un eye catcher (ou on en ajoute un à dans chaque structure) ?
    
./Post n°65   Marquer comme non lu.
Quésoft Ecrit le: Samedi 21 octobre 2006 à 00:22 Déconnecté(e)    Voir le profil de Quésoft Envoyer un email à Quésoft Visiter le site WEB de Quésoft Envoyer un message privé à Quésoft  

Je vois maintenant que c'est ce que tu proposais:

Enfin c'est possible de façon un peu crade sans modification du compilo, si les stack frames sont activés : il suffit de mettre un marqueur magique aléatoire pour les objets à détruire, et rechercher le marqueur dans la pile...
    
./Post n°66   Marquer comme non lu.
Kevin Kofler Ecrit le: Samedi 21 octobre 2006 à 01:41 Déconnecté(e)    Voir le profil de Kevin Kofler Envoyer un email à Kevin Kofler Visiter le site WEB de Kevin Kofler Envoyer un message privé à Kevin Kofler  


Pollux :
Non, les métadonnées c'est si le compilo les supporte (sinon évidemment il y a un overhead et ça sert plus à rien), mais sinon la méthode du scan de la pile devrait pas trop mal marcher et apporter de gros gains de place et de vitesse :) (et en fait tu peux même te débrouiller pour pas avoir besoin de stack frame du tout)

Sauf que c'est un hack sauvage et que s'il fait ce hack avec GCC 4.1.2, rien ne dit qu'il fonctionne encore avec GCC 4.2.0 voire 4.1.3. #roll# Et tu fais quoi si la valeur aléatoire que tu scannes est par hasard dans un tableau de données? Plantage! #roll# Et si GCC décide de scalariser un ou deux membres de la structure (chose que GCC peut faire depuis la version 4.0)? S'il n'y a pas de prise d'adresse visible (et au bon endroit!), c'est tout à fait possible, et quand ton destructeur veut lire la structure entière sur la pile -> boum! #roll#
-Edité le Samedi 21 octobre 2006 à 01:43 par Kevin Kofler-
Membre de l'équipe de TIGCC: http://tigcc.ticalc.org
Mainteneur du portage Linux/Unix de TIGCC: http://tigcc.ticalc.org/linux/
Membre de l'équipe de CalcForge: http://www.calcforge.org:70/

Participez à la reprise de Ti-Gen!
    
./Post n°67   Marquer comme non lu.
Kevin Kofler Ecrit le: Samedi 21 octobre 2006 à 01:47 Déconnecté(e)    Voir le profil de Kevin Kofler Envoyer un email à Kevin Kofler Visiter le site WEB de Kevin Kofler Envoyer un message privé à Kevin Kofler  


La bonne solution est d'utiliser un TRY...FINALLY...ENDFINAL pour le nettoyage, et de convertir les exit (si vraiment quelqu'un a la mauvaise idée d'appeler ça au lieu de lancer une exception) en des ER_throw.
Membre de l'équipe de TIGCC: http://tigcc.ticalc.org
Mainteneur du portage Linux/Unix de TIGCC: http://tigcc.ticalc.org/linux/
Membre de l'équipe de CalcForge: http://www.calcforge.org:70/

Participez à la reprise de Ti-Gen!
    
./Post n°68   Marquer comme non lu.
Quésoft Ecrit le: Samedi 21 octobre 2006 à 05:55 Déconnecté(e)    Voir le profil de Quésoft Envoyer un email à Quésoft Visiter le site WEB de Quésoft Envoyer un message privé à Quésoft  

Kevin Kofler :
Sauf que c'est un hack sauvage et que s'il fait ce hack avec GCC 4.1.2, rien ne dit qu'il fonctionne encore avec GCC 4.2.0 voire 4.1.3. #roll# Et tu fais quoi si la valeur aléatoire que tu scannes est par hasard dans un tableau de données? Plantage! #roll# Et si GCC décide de scalariser un ou deux membres de la structure (chose que GCC peut faire depuis la version 4.0)? S'il n'y a pas de prise d'adresse visible (et au bon endroit!), c'est tout à fait possible, et quand ton destructeur veut lire la structure entière sur la pile -> boum! #roll#


Il y a aussi que c'est hardware dependent.

Kevin Kofler :
La bonne solution est d'utiliser un TRY...FINALLY...ENDFINAL pour le nettoyage, et de convertir les exit (si vraiment quelqu'un a la mauvaise idée d'appeler ça au lieu de lancer une exception) en des ER_throw.


encore là... on n'a pas toujours ce luxe: immaginons que la fonction appelée est dans un autre module, fourni par une tierce personne. Dans ce cas, on ne pourra convertir une instruction exit.

Honêtement, gérer les objets locaux en espérant un overhead minimum est utopique (pour un préprocesseur). Il n'y a pas de solution miracle. C'est un point en faveur du frontend.

Si je reste avec un préprocesseur, c'est partie pour être la méthode Moka avec certaines optimisations (si l'objet n'a pas de destructeur, il ne sera pas ajouté à la liste des locaux. si aucun objet local n'a de destructeur, pas de atexit et pas de liste d'objets locaux).

D'une façon ou d'une autre, le tokenizer étant déjà programmé, ce ne sera pas une grande perte de temps de coder un préprocesseur en premier lieu, même si je finit par travailler sur un frontend. Je répète que cette dernière solution est moins conviviale, puisque j'aimerais bien développer quelque chose d'assez universel.
-Edité le Samedi 21 octobre 2006 à 05:58 par Quésoft-
    
./Post n°69   Marquer comme non lu.
Kevin Kofler Ecrit le: Samedi 21 octobre 2006 à 12:29 Déconnecté(e)    Voir le profil de Kevin Kofler Envoyer un email à Kevin Kofler Visiter le site WEB de Kevin Kofler Envoyer un message privé à Kevin Kofler  


Quésoft :
encore là... on n'a pas toujours ce luxe: immaginons que la fonction appelée est dans un autre module, fourni par une tierce personne. Dans ce cas, on ne pourra convertir une instruction exit.

Dans le contexte de TIGCC (qui est le seul auquel ER_throw s'applique), tu ne trouveras normalement pas de libraries qui osent appeler exit. (Si tu en vois une, signale-la moi pour que j'aille frapp^H^H^H^H^Hconvaincre l'auteur de changer ça. :) exit ne fait aucun nettoyage dans TIGCC, donc ça n'a vraiment rien à faire dans une lib générique.)

Sur PC, exit fait un unwinding pour la gestion des exceptions normalement, du moins sous Linux. Donc si tu compiles avec -fexceptions, tu peux utiliser __attribute__((__cleanup__(myclass_dtor))), un nouvel attribut de GCC 4.1 (ou 4.0?) qui sert exactement à ça. Enfin bon, sur PC, autant utiliser g++ ou GCJ plutôt que ton préprocesseur!
Membre de l'équipe de TIGCC: http://tigcc.ticalc.org
Mainteneur du portage Linux/Unix de TIGCC: http://tigcc.ticalc.org/linux/
Membre de l'équipe de CalcForge: http://www.calcforge.org:70/

Participez à la reprise de Ti-Gen!
    
./Post n°70   Marquer comme non lu.
Pollux Ecrit le: Samedi 21 octobre 2006 à 13:21 Déconnecté(e)    Voir le profil de Pollux Envoyer un email à Pollux Envoyer un message privé à Pollux  

Kevin Kofler :
Sauf que c'est un hack sauvage et que s'il fait ce hack avec GCC 4.1.2, rien ne dit qu'il fonctionne encore avec GCC 4.2.0 voire 4.1.3. #roll#

Ben pourquoi #confus# Les seules garanties dont on a besoin qui ne soient pas dans le standard C, c'est :
- une structure locale dont on passe l'adresse à une fonction externe est toujours allouée sur la pile
- la pile se trouve toujours *après* a7
- si la fonction f appelle la fonction g les variables locales de g seront toujours avant celles de f
Je pense pas qu'un compilo TI ait l'intention de violer ces conventions :)
(la seule qui soit un peu problématique, c'est la 1ère : un compilo qui se rend compte qu'une fonction n'est pas réentrante pourrait en principe décider d'allouer une structure locale dans le segment data, mais l'intérêt me paraît limité et en tout cas ce n'est implémenté ni dans gtc ni dans gcc, aux dernières nouvelles)

Enfin dans tous les cas je pense que c'est une bonne idée de permettre plusieurs modes de fonctionnement, un "portable mais gros et lent" et un "efficace mais platform-dependent" :)

Et tu fais quoi si la valeur aléatoire que tu scannes est par hasard dans un tableau de données? Plantage! #roll#

Ben oui, mais dans la mesure où c'est randomisé ce n'est pas une vulnérabilité qui peut être exploitée : c'est qqch qui ne peut arriver qu'avec une probabilité bornée (si le marqueur est sur 64 bits, la probabilité que le bug arrive est très faible même si tu laisses tourner ta caltos 24h/24 pendant plusieurs millénaires %) y a sûrement plus de chances qu'un rayon cosmique altère un bit de ta ram bien avant...)

Et si GCC décide de scalariser un ou deux membres de la structure (chose que GCC peut faire depuis la version 4.0)? S'il n'y a pas de prise d'adresse visible (et au bon endroit!), c'est tout à fait possible, et quand ton destructeur veut lire la structure entière sur la pile -> boum! #roll#

On a plusieurs solutions :
- déclarer la structure en volatile -- très mauvais pour les performances
- considérer le constructeur comme une fonction opaque : du coup le compilo est bien obligé d'allouer une adresse pour l'objet et de s'y tenir, et il doit garantir l'intégrité de la structure à chaque appel d'une fonction externe style exit() ou throw_exception() -- pas mal, mais encore un problème : ça empêche d'inliner le constructeur
- ne pas considérer le constructeur comme une fonction opaque, mais appeler à la fin du constructeur une fonction opaque qui aurait pour paramètre la structure (ou utiliser un asm() vide pour ne générer aucun code) -- idéal niveau performance :)

Et puis du point de vue des performances, outre le fait que ça évite un appel coûteux à ER_catch (et que ça évite aussi de gâcher de la place dans le code de récupération d'erreur), ça évite aussi de devoir marquer des variables qui pourraient aller dans des registres comme volatile, et ça évidemment ça va avoir un impact énorme ^^


Bref, je suis bien d'accord que c'est crade, mais ça me paraît quand même être une solution honnête si Quesoft n'a pas envie de rajouter des extensions au compilo...
    
./Post n°71   Marquer comme non lu.
Quésoft Ecrit le: Samedi 21 octobre 2006 à 13:55 Déconnecté(e)    Voir le profil de Quésoft Envoyer un email à Quésoft Visiter le site WEB de Quésoft Envoyer un message privé à Quésoft  

Pollux :

Enfin dans tous les cas je pense que c'est une bonne idée de permettre plusieurs modes de fonctionnement, un "portable mais gros et lent" et un "efficace mais platform-dependent" :)


C'est à considérer, en effet. Mais je ne pense pas que le portable optimisé sera outrageusement plus gros et lent.

Pollux :
Et tu fais quoi si la valeur aléatoire que tu scannes est par hasard dans un tableau de données? Plantage! #roll#

Ben oui, mais dans la mesure où c'est randomisé ce n'est pas une vulnérabilité qui peut être exploitée : c'est qqch qui ne peut arriver qu'avec une probabilité bornée (si le marqueur est sur 64 bits, la probabilité que le bug arrive est très faible même si tu laisses tourner ta caltos 24h/24 pendant plusieurs millénaires %) y a sûrement plus de chances qu'un rayon cosmique altère un bit de ta ram bien avant...)


J'avais bien déduit que vous proposiez d'utiliser un quelque chose de semblable à un hash comme tag :)
    
./Post n°72   Marquer comme non lu.
Quésoft Ecrit le: Samedi 21 octobre 2006 à 13:59 Déconnecté(e)    Voir le profil de Quésoft Envoyer un email à Quésoft Visiter le site WEB de Quésoft Envoyer un message privé à Quésoft  

Kevin Kofler :
Quésoft :
encore là... on n'a pas toujours ce luxe: immaginons que la fonction appelée est dans un autre module, fourni par une tierce personne. Dans ce cas, on ne pourra convertir une instruction exit.

Dans le contexte de TIGCC (qui est le seul auquel ER_throw s'applique), tu ne trouveras normalement pas de libraries qui osent appeler exit. (Si tu en vois une, signale-la moi pour que j'aille frapp^H^H^H^H^Hconvaincre l'auteur de changer ça. :) exit ne fait aucun nettoyage dans TIGCC, donc ça n'a vraiment rien à faire dans une lib générique.)


On peut aussi livrer en labelant un warning du genre 'ne pas mélanger conduite automobile, objets locaux et fonction exit', mais je trouve ça louche comme solution. Également l'overhead d'un TRY ... FINALLY représente quoi à peu près ?

Kevin Kofler :
Enfin bon, sur PC, autant utiliser g++ ou GCJ plutôt que ton préprocesseur!


C'est pourquoi le but de ce préprocesseur est de produire du ANSI-C: il va pouvoir servir sur les environnements qui n'ont pas de GCC ou d'autres compilateurs C++.
    
./Post n°73   Marquer comme non lu.
Quésoft Ecrit le: Samedi 21 octobre 2006 à 14:00 Déconnecté(e)    Voir le profil de Quésoft Envoyer un email à Quésoft Visiter le site WEB de Quésoft Envoyer un message privé à Quésoft  

En tk, je pense que je commencerai par implémenter les objets alloués dynamiquement!
-Edité le Samedi 21 octobre 2006 à 14:00 par Quésoft-
    
./Post n°74   Marquer comme non lu.
Pollux Ecrit le: Samedi 21 octobre 2006 à 14:51 Déconnecté(e)    Voir le profil de Pollux Envoyer un email à Pollux Envoyer un message privé à Pollux  

Bonne idée, parce que tu vas avoir une montagne de problème avec les objets alloués statiquement :)


Quésoft :
J'avais bien déduit que vous proposiez d'utiliser un quelque chose de semblable à un hash comme tag :)

Ben ce serait pas un hash, ce serait un truc aléatoire calculé une fois pour toutes au début du programme...


Quésoft :
Honêtement, gérer les objets locaux en espérant un overhead minimum est utopique (pour un préprocesseur). Il n'y a pas de solution miracle. C'est un point en faveur du frontend.

Je ne pense pas qu'un frontend spécifique à un compilo soit une très bonne idée : tu perds la portabilité, et ça risque d'être bien plus compliqué à écrire (et surtout à maintenir). Si tu as besoin d'un truc comme le support des exceptions, je pense que la meilleure idée serait plutôt de patcher juste ce qu'il faut dans le compilateur C pour qu'il te fournisse les informations dont tu as besoin (où sont les objets sur la pile, etc)

Si je reste avec un préprocesseur, c'est partie pour être la méthode Moka avec certaines optimisations (si l'objet n'a pas de destructeur, il ne sera pas ajouté à la liste des locaux. si aucun objet local n'a de destructeur, pas de atexit et pas de liste d'objets locaux).

Tu veux utiliser atexit dans chaque fonction ? Pourquoi ? #confus#




Euh sinon c'est qd même assez dangereux de mélanger sémantique de pointeur (équivalent en C++ : String *) et sémantique de valeur (équivalent en C++ : String), il faut absolument réfléchir là-dessus... Par exemple, si je travaille sur un arbre : il y a une classe de base Node pour représenter un noeud quelconque, dérivée en une classe LeafNode pour les feuilles et une classe InnerNode pour les noeuds internes.
Déjà il y a le cas où j'ai une fonction CreateLeafNode() qui est "presque" un constructeur :
auto LeafNode node = CreateLeafNode(plop);

Le problème, c'est évidemment que CreateLeafNode() va appeler malloc() lui-même, et qu'après ça on sera bien embêté pour copier le LeafNode -- peut-être qu'on pourra le copier quand même sur la pile si LeafNode a un constructeur de copie, mais il y a peut-être de très bonnes raisons pour qu'il n'en ait pas et alors on est foutu.
La solution ça serait que CreateLeafNode() ait un moyen de dire "tiens tiens, ça m'arrangerait qu'on me passe en paramètre un bloc de mémoire où je pourrais mettre mon LeafNode, et que si personne ne s'en sert il soit libéré" -- oh, mais c'est exactement la définition de "auto" =) Du coup on pourrait déclarer CreateLeafNode() avec :
auto LeafNode CreateLeafNode(...);

au lieu de
LeafNode CreateLeafNode(...);


En fait je dirais que CreateLeafNode() est un "constructeur étendu" de LeafNode : il n'est pas fondamentalement différent d'un appel de constructeur du style new LeafNode(...) :) Je pense que ce serait une bonne idée de ne jamais pouvoir affecter à un auto LeafNode autre chose qu'un appel de constructeur étendu, sinon ce serait très très casse-gueule parce que l'affectation à un auto LeafNode n'aurait pas du tout la même sémantique que l'affectation à un LeafNode tout court ^^

Mais il y a encore un problème : si maintenant j'ai une fonction CreateNode() qui peut créer soit un LeafNode soit un InnerNode (et qui renvoie donc un Node), qu'est-ce qu'il va se passer si je fais
auto Node node = CreateNode(plop);

? Le problème c'est qu'un bloc de taille sizeof(Node) n'est pas forcément assez grand pour contenir un LeafNode ou un InnerNode...
On peut ignorer le problème en disant qu'on a pas le droit de faire ça, mais je trouve que ça casserait vraiment la mentalité OO ; il y a plusieurs solutions, de la moins bien à la meilleure :
- solution triviale, considérer qu'un "auto Node" est juste un Node (donc un pointeur) libéré automatiquement en fin de vie -- évidemment c'est bcp trop lent
- considérer qu'un auto Node est un pointeur, mais allouer juste assez d'espace pour un Node -- si le résultat tient dans un Node, on évite le malloc, mais dans les autres cas ça marche quand même grâce au pointeur
- réserver de l'espace pour la plus grosse classe dérivée de Node -- incompatible avec la compilation séparée, et il peut y avoir du gâchis, mais simple et très efficace
- pour chaque constructeur étendu, avoir une annotation générée par le compilo donnant la liste exhaustive des types de retour -- extrêmement délicat à implémenter, mais idéal
    
./Post n°75   Marquer comme non lu.
Quésoft Ecrit le: Samedi 21 octobre 2006 à 16:10 Déconnecté(e)    Voir le profil de Quésoft Envoyer un email à Quésoft Visiter le site WEB de Quésoft Envoyer un message privé à Quésoft  

Pollux :
Quésoft :
J'avais bien déduit que vous proposiez d'utiliser un quelque chose de semblable à un hash comme tag :)

Ben ce serait pas un hash, ce serait un truc aléatoire calculé une fois pour toutes au début du programme...


Mais ça va être pas mal semblable à un hash... Quand j'ai besoin d'un nonce, je fais quelque chose du genre (en php):

md5(mt_rand());

et je prend la longueur qu'il me faut. Je sais que c'est pas nécessairement un hash que ça prend, mais le résultat sera similaire.

Pollux :
Je ne pense pas qu'un frontend spécifique à un compilo soit une très bonne idée : tu perds la portabilité, et ça risque d'être bien plus compliqué à écrire (et surtout à maintenir). Si tu as besoin d'un truc comme le support des exceptions, je pense que la meilleure idée serait plutôt de patcher juste ce qu'il faut dans le compilateur C pour qu'il te fournisse les informations dont tu as besoin (où sont les objets sur la pile, etc)


Reste le problème que l'on est dépendant non seulement du compilateur, mais de sa version. À chaque fois qu'un compilo évolue, il faut le repatcher.

Pollux :
Tu veux utiliser atexit dans chaque fonction ? Pourquoi ? #confus#


Il n'y a qu'un atexit qui est pas très gras: petite boucle qui exécute les destructeurs... À moins que l'on puisse déenregistrer un atexit ?


Pollux :
Euh sinon c'est qd même assez dangereux de mélanger sémantique de pointeur (équivalent en C++ : String *) et sémantique de valeur (équivalent en C++ : String), il faut absolument réfléchir là-dessus... Par exemple, si je travaille sur un arbre : il y a une classe de base Node pour représenter un noeud quelconque, dérivée en une classe LeafNode pour les feuilles et une classe InnerNode pour les noeuds internes.
Déjà il y a le cas où j'ai une fonction CreateLeafNode() qui est "presque" un constructeur :
auto LeafNode node = CreateLeafNode(plop);

Le problème, c'est évidemment que CreateLeafNode() va appeler malloc() lui-même, et qu'après ça on sera bien embêté pour copier le LeafNode -- peut-être qu'on pourra le copier quand même sur la pile si LeafNode a un constructeur de copie, mais il y a peut-être de très bonnes raisons pour qu'il n'en ait pas et alors on est foutu.
La solution ça serait que CreateLeafNode() ait un moyen de dire "tiens tiens, ça m'arrangerait qu'on me passe en paramètre un bloc de mémoire où je pourrais mettre mon LeafNode, et que si personne ne s'en sert il soit libéré" -- oh, mais c'est exactement la définition de "auto" =) Du coup on pourrait déclarer CreateLeafNode() avec :
auto LeafNode CreateLeafNode(...);

au lieu de
LeafNode CreateLeafNode(...);


En fait je dirais que CreateLeafNode() est un "constructeur étendu" de LeafNode : il n'est pas fondamentalement différent d'un appel de constructeur du style new LeafNode(...) :) Je pense que ce serait une bonne idée de ne jamais pouvoir affecter à un auto LeafNode autre chose qu'un appel de constructeur étendu, sinon ce serait très très casse-gueule parce que l'affectation à un auto LeafNode n'aurait pas du tout la même sémantique que l'affectation à un LeafNode tout court ^^


CreateLeafNode est une genre de object factory. C'est vrai que c'est utilisé souvent. On peut faire allouer dynamiquement les noeuds pour régler le problème.

Pollux :
Mais il y a encore un problème : si maintenant j'ai une fonction CreateNode() qui peut créer soit un LeafNode soit un InnerNode (et qui renvoie donc un Node), qu'est-ce qu'il va se passer si je fais
auto Node node = CreateNode(plop);



Comme en C++, cette asignation ne pourra pas marcher. Même si je souhaite que la manipulation des objets locaux soit comparable à celle des objets non locaux, je ne pourrai pas évidemment faire des miracles (à moins d'implémenter un GC, ce qui n'est pas dans mes plans). Ainsi, on devra faire un new pour ça:

Node node = CreateNode(plop);


Pollux :
? Le problème c'est qu'un bloc de taille sizeof(Node) n'est pas forcément assez grand pour contenir un LeafNode ou un InnerNode...
On peut ignorer le problème en disant qu'on a pas le droit de faire ça, mais je trouve que ça casserait vraiment la mentalité OO ; il y a plusieurs solutions, de la moins bien à la meilleure :
- solution triviale, considérer qu'un "auto Node" est juste un Node (donc un pointeur) libéré automatiquement en fin de vie -- évidemment c'est bcp trop lent
- considérer qu'un auto Node est un pointeur, mais allouer juste assez d'espace pour un Node -- si le résultat tient dans un Node, on évite le malloc, mais dans les autres cas ça marche quand même grâce au pointeur
- réserver de l'espace pour la plus grosse classe dérivée de Node -- incompatible avec la compilation séparée, et il peut y avoir du gâchis, mais simple et très efficace
- pour chaque constructeur étendu, avoir une annotation générée par le compilo donnant la liste exhaustive des types de retour -- extrêmement délicat à implémenter, mais idéal

J'irais pour 'réserver de l'espace pour la plus grosse classe dérivée de Node' (parce que pour l'instant, le préproc ne permettra pas la compilation séparée - pour les features OO, évidemment). Mais je ne suis pas sûr que ce soit d'un grand secours de supporter cette feature (bien que c'est vrai que c'est plus respectueux du paradigme OO et surtout plus cohérent): si j'ai un arbre avec de la récursion, je ne pourrai pas m'en sortir dans allocation dynamique. Dans ce cas, aussi bien faire se servir d'un objet Tree servant en local qui s'occupera de la finalization (tactique employée souvent en C++ je crois).


auto Tree t;

t.methode_quelconque(CreateLeafNode(...)); //CreateLeafNode utilise new pour l'allocation.


-Edité le Samedi 21 octobre 2006 à 16:11 par Quésoft-
    
./Post n°76   Marquer comme non lu.
Onur Ecrit le: Samedi 21 octobre 2006 à 16:35 Déconnecté(e)    Voir le profil de Onur Envoyer un email à Onur Visiter le site WEB de Onur Envoyer un message privé à Onur  


Pour les spécs, tout ce que je veux, c'est qu'on puisse hériter et gérer un minimum de polymorphisme pour faire ce que j'ai dit plus haut... Càd hériter d'une classe Sprite dont l'affichage et les collisions dans une map sont automatiquement gérés grace à des routines écrites en asm.

La, je sais pas si vous vous rendez compte, mais j'ai l'impression qu'on design d'un outil qui va vraiment apporter à la communauté. Et le fait que l'auteur ne soit pas un waporman me plait bcp. (Parce qu'il y en avait marre des mecs qui viennent poster pour faire un compilo et qui foutent rien, bref)
Je ne veux pas faire quelque chose de bien, je cherche l'excellence:ETP Studio...


et autres projets à finir avant 2010
    
  :: Index » Forum Ti68K » Programmation C » Orienté objet avec TIGCC (113 réponse(s))
Pages : 4/6     « 1 2 3 [4] 5 6 » »|

.Répondre à ce sujet
Les boutons de code
[B]old[I]talic[U]nderline[S]trikethrough[L]ine Flip Hori[Z]ontallyFlip [V]erticallySha[D]ow[G]low[S]poilerCode [G][C]ite
Bullet [L]istList Item [K] Link [H][E]mail[P]icture SmileysHelp
Couleurs :
Saisissez votre message
Activer les smileys
     

Forum de Ti-Gen v3.0 Copyright ©2004 by Geoffrey ANNEHEIM
Webmaster: Kevin KOFLER, Content Admins: list, Server Admins: Tyler CASSIDY and Kevin KOFLER, DNS Admin: squalyl
Page générée en 57.48ms avec 18 requetes