30

1. Un objet pouvant utiliser un systeme de cache ne peut pas etre declare de const.
2. Tu ajustes au cas pas cas. Normalement une simple edition du .h .c suffit.
3. Dans ce cas tu refais l'implantation de ton module. Ce n'est absolument pas dur si tu as code correctement en C.

M'enfin, si ca marche pas c'est ta faute et pas celle du C. Le const marche tres bien.

31

1. C'est bien là tout le problème. Si tu veux rajouter une méthode à un objet et que tu veux mettre un cache sur le résultat, tu es obligé de _tout_ changer. Je ne parle même pas de l'efficacité comparé à const+mutable, qui est ridicule.
2. C'est déjà plutôt chiant, et donc pour moi c'est un hack.
3. Ben, il faut virer tous les const, quoi. La macro n'apporte rien, puisqu'il faut toujours appliquer ./3.

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

32

1. _tout_ changer : Faut pas exagerer non plus... Tu rajoutes une nouvelle methode avec cache puis basta.
2. const+mutable : Ben tu fais le casting de Kevin. Ca marche, et vu tes considerations standardisiennes, ca sera suffisant.

33

1. Non, on est obligé de supprimer tous les const qui se rapportent à un IDENT, pour peu qu'il y ait un peu de récursion qq part. Tout ça à cause d'UN appel d'UNE méthode avec cache, qui ne change rien au plan sémantique.
2. Ca ne marche pas, comme je l'ai expliqué, ou alors peut-être que c'est parce que je ne comprends pas ce que tu sous-entends par "[mes] considerations standardisiennes"...

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

34

Solution simple: pas de cache, ou alors cache initialisé lors de la construction (ou l'initialisation de structure), comme ça ta classe est vraiment constante.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

35

Dans le cas où le problème est apparu, le problème est que la valeur à mettre en cache ne peut pas encore être calculée au moment du parsing (c'était pour un simulateur de circuit digital synchrone, on accepte une liste de relations entre les valeurs des fils, les déclarations pouvant être faites dans n'importe quel ordre, donc on n'a pas encore le pointeur vers SYM). Evidemment, il y a aussi la solution de recréer une autre structure (une avant la mise en cache, une après), mais ça pose aussi d'autres problèmes et c'est plus lourd.

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

36

1. Je suis desole mais mettre un cache change la semantique. Donc c'est tout a fait normal.
2. En C pratique ca marche tongue

37

1. Oui, et c'est le "mutable" qui est le témoin du changement de sémantique entre "structure sans cache" et "structure avec cache". Ca n'empêche que c'est ridicule que lorsque *un seul* membre se met à avoir un cache, tous les accès à la structure deviennent soudainement interdits avec le "const".
2. confus

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

38

1. En quoi c'est ridicule ?
2. Ca marche quand meme.

39

!slap PpHd
• Thibaut slaps PpHd around a bit with a large trout !

!slap Pollux
• Thibaut slaps Pollux around a bit with a large trout !
avatar
Un site complet sur lequel vous trouverez des programmes et des jeux pour votre calculatrice TI 89 / Titanium / 92+ / Voyage 200 : www.ti-fr.com.
Quelques idées personnelles ici.

40

Tu peux aussi faire:

typedef struct {
  SYM **symbol;
  char name[];
} IDENT;

long GetSize(const IDENT *i) {
  if (!*(i->symbol)) {
    *(i->symbol)=...;  // Ok.
  }
  return i->symbol.size;
}

ie implanter le mutable a la main. tongue (Et ceci dit il est de bon ton d'acceder aux champs de ta structure via des macros. Dans ce cas tu n'aurais rien eu a changer tongue).

41

Oui, mais au niveau performance il y a un gros problème... (une indirection en plus + 4 octets en plus + coût du code d'initialisation qui doit allouer ailleurs) C'est d'autant plus dommage que le C est censé être plus bas niveau que le C++, alors que dans ce cas-là c'est exactement le contraire qui se passe! Donc je trouve que 'const' est plutôt mal implémenté.

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

42

NON IL EST PARFAIT !!
C'est en C++, que le const ne sert a rien.
Et le coup du cache avec le mutable, je l'ai repris d'une implantation C++ grin

43

NON IL EST PARFAIT !!

Apparemment non puisque tu es obligé d'allouer séparément ton SYM *.
C'est en C++, que le const ne sert a rien.

grep mutable *.cpp *.h
pour voir les endroits où il "sert à rien". Et le fait de "servir à rien" ne concerne que les seuls membres marqués de mutable (au maximum une petite dizaine sur tout un projet); alors que si on doit enlever les const partout, ça concerne toutes les occurrences de la structure en question...
Et le coup du cache avec le mutable, je l'ai repris d'une implantation C++ grin

De quoi, ce que t'as mis dans ./40 ?

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

44

Mon const il est const. Pas celui du C++!

grep mutable *.cpp *.h : 0 tongue

ou'e

45

. Erf, fais pas ton Kevin wink Il y a clairement et de manière documentée une exception pour les champs marqués "mutable". Alors que si tu te contentes de supprimer les "const" des structures où il y a un cache, tu es obligé à chaque fois de te poser la question "est-ce que la structure est censée être modifiée ou pas par la fonction que j'appelle?" puisqu'il n'y a pas de "const", et tu as du mal à bien faire la différence entre passage d'une valeur et passage d'une valeur qui sera modifiée.
Et, chose indéniable, le code généré est bien meilleur avec un "mutable" que sans...

. Oui, si tu n'en as pas besoin, ne t'en sers pas. Perso j'en ai déjà eu besoin plusieurs fois.

. C pas de ma faute si tu reprends des sources mal programmées tongue

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

46

La conception du C++ est une daube en soie. Un const est un const. mutable est le reflet de la conception du C++ : on veut un const, puis en fait non, on en veut pas. triso

47

N'importe quoi. C'est juste symptomatique du fait qu'il y a une abstraction de l'implémentation physique de l'objet pour passer au niveau sémantique (et donc ça se place au même niveau que les constructeurs/destructeurs). Ca permet d'avoir des "const smart_ptr<mystruct>" qui veulent vraiment dire ce qu'ils veulent dire, i.e. que le pointeur en question est constant. Pas que l'implémentation n'a pas le droit de faire sa magouille en bas niveau.

Et tu n'as pas bronché quand j'ai dit que ça permettait aussi de faire du code plus performant, je prends ça comme une approbation...

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

48

C'est surtout que j'ai pas compris en quoi ca permettait de faire du code plus performant...

Et dans ton exemple, le pointeur n'est pas constant....

Et puis tu m'enerves : le cast de const en rien marche tres bien pour l'implantation bas niveau. C'est pas portable en toute serenite, c'est tout.

49

C'est surtout que j'ai pas compris en quoi ca permettait de faire du code plus performant...

// utils.c
void CalcDim(LINE *s) {
  s->w=0; s->h=0;
  s->p=s->p0; s->style=s->style0;
  while (*s->p++) {
    int x,y;
    CalcChar(s,&x,&y,0);
    s->w+=x; s->h=max(s->h,y);
  }
}

// chars.c
FONT *CachedFontLookup(FONT **cache,STYLE *style) {
  ...
}
void CalcChar(LINE *s,int *x,int *y,int do_draw) { // pas de 'const LINE *' puisqu'on utilise un cache
  ...
  FONT *f=CachedFontLookup(&s->font,&s->style);
  ...
}

Le compilo est obligé d'aller rechercher s->w, s->h et s->p à chaque fois parce qu'il ne sait pas qu'ils ne sont pas modifiés... Avec un mutable et un 'const LINE *', le compilo pourrait l'optimiser.
Et dans ton exemple, le pointeur n'est pas constant....

Le pointeur est constant dans le sens où toutes les opérations qu'on peut faire dessus (déréférencement, affectation) se comporteront exactement de la même manière. A partir de là, je ne vois pas ce qu'il a de non constant (à part au niveau binaire, mais justement l'utilisateur n'a pas à s'en préoccuper).
Et puis tu m'enerves : le cast de const en rien marche tres bien pour l'implantation bas niveau. C'est pas portable en toute serenite, c'est tout.

Bon, en fait ça me semblait évident qu'une fonction "void f(const foo *x);" n'avait pas le droit de modifier 'x' (à moins de pouvoir y accéder autrement, par exemple via une var globale). Mais le standard C n'a pas l'air d'être clair sur ce point. En gros, ma question est, est-ce que ce code est légal / a un comportement défini (renvoyer 0) dans n'importe quelle implémentation ANSI :
void sub(const int *x) {
  *(int *)x=0;
}
int func() {
  int x=1;
  sub(&x);
  return x;
}

En tout cas GCC 3.3.1 n'a pas l'air d'avoir du tout envie de transformer le 'return x' en 'return 1'... (même en déclarant sub() dans un fichier séparé)

Alors si le standard C autorise le code précédent et spécifie qu'il renvoie 0, le hack marche effectivement parfaitement (mais alors 'const' n'est qu'un truc pour empêcher des erreurs); si ce n'est pas le cas, alors la solution que tu proposes a toutes les chances de foirer tôt ou tard en faisant une modification mineure du code...

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

50


Le compilo est obligé d'aller rechercher s->w, s->h et s->p à chaque fois parce qu'il ne sait pas qu'ils ne sont pas modifiés... Avec un mutable et un 'const LINE *', le compilo pourrait l'optimiser.

1. Tu peux toujours faire un vrai systeme de cache.
2. Tu peux faire des castings de structures.
3. Tu peux reecrire ton code pour que le compilo optimise.
4. De toute facon, ca m'etonnerait fortement que ca soit ca qui soit a optimiser dans ton programme...

Le pointeur est constant dans le sens où toutes les opérations qu'on peut faire dessus (déréférencement, affectation) se comporteront exactement de la même manière. A partir de là, je ne vois pas ce qu'il a de non constant (à part au niveau binaire, mais justement l'utilisateur n'a pas à s'en préoccuper).

Ce qui n'est pas la definition d'un pointeur constant.

Alors si le standard C autorise le code précédent et spécifie qu'il renvoie 0, le hack marche effectivement parfaitement (mais alors 'const' n'est qu'un truc pour empêcher des erreurs); si ce n'est pas le cas, alors la solution que tu proposes a toutes les chances de foirer tôt ou tard en faisant une modification mineure du code...

Non, il ne l'autorise pas.
Mais tu peux le declarer en const volatile si tu veux grin
La c'est correct cool.

51

1. Tu peux toujours faire un vrai systeme de cache.

Mais moins efficace.
2. Tu peux faire des castings de structures.

Je ne vois pas ce que tu veux dire. Virer le const? Tu dis toi-même que c'est illégal (à moins de rajouter volatile, ce qui est top niveau efficacité tongue)
3. Tu peux reecrire ton code pour que le compilo optimise.

Comment? Pour que ça soit le cas, il faudrait intégrer le code de 'chars.c' dans 'utils.c', et il faudrait aussi que le compilo soit assez bon; ce n'est pas tjs possible (lib dynamique...), et en plus un compilo tel que GCC n'est pas assez bon pour le faire (sauf qd il inline la fonction, mais c svt loin d'être une bonne idée...)
4. De toute facon, ca m'etonnerait fortement que ca soit ca qui soit a optimiser dans ton programme...

Oui. Mais reconnais au moins que le code généré est moins bon, et qu'en plus au niveau sémantique ça ne correspond pas à ce qu'on peut vouloir (surtout si le développeur de la classe qui utilise un mutable est distinct de celui du prog qui utilise cette classe).
Ce qui n'est pas la definition d'un pointeur constant.

Pff, ça ne veut rien dire. Tu peux aussi t'imaginer que le mot-clé "mutable" est un wrapper du même style que le symbole "*" : son contenu n'est pas read-only, même quand il est en read-only. La différence étant que c'est un wrapper vers un objet unique alloué dans la structure, donc qu'il n'y a pas besoin de modifier l'adresse de ce vers quoi il pointe, donc qu'on peut omettre l'étoile pour y accéder.
Tu ne vas pas me dire qu'une structure est plus constante si je fais "SYM** foo;" que si je fais "mutable SYM* foo;" (la différence est que dans le deuxième cas, c'est le compilo qui s'occupe de l'allocation, et que le code est plus efficace parce qu'il n'y a pas besoin de pointeur supplémentaire).
Non, il ne l'autorise pas.

OK, merci. Tu en es absolument sûr? (que je ne mette pas dans GTC des "optimisations" interdites par le standard)

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

52

1. Pas vraiment. Je veux voir l'implantation C++ reelle.
2. Nan, tu inseres ton const dans ta structure que tu castes a la voler. Tres sale.
3. La fonction CaclDim.
5. Tu confonds pointeur constant et pointeur vers un object constant.
6. Pas a 100% mais bien a 90%.
7. Tu definis ton interface utilisateur avec const volatile * et a l'interieur avec de simples ptr *. La aussi c'est non-portables, mais tu as des chances d'eviter des problemes.

53

1. struct ID { mutable SYM *cached_sym; char name[]; SYM *sym() const { if (!cached_sym) cached_sym=Find(name); return cached_sym; } };
Je veux bien voir comment tu fais plus efficace.
2. Je ne vois pas comment tu peux faire comme ça sans casser la compatibilité ANSI.
3. Ah oui. Mais 1) ça devient vite relou (on n'est plus à l'époque des variables 'register') et 2) comme le compilo n'est pas capable d'établir l'équivalence des 2 représentations, si par hasard tu "optimises" trop de variables pour le nombre de registres du processeur, ton code est moins bon (et donc ton code ne sera efficace que sur une plateforme donnée)
5. Non, justement neutral Considère qu'un "mutable int" est un wrapper (éventuellement constant) vers un "int" (non-constant), de même qu'un "int *" est un wrapper (éventuellement constant) vers un "int" (non-constant). Je ne vois pas en quoi dans le premier cas, ce serait contraire à la 'philosophie' du "const", alors que dans le second cas non...
7. Mais c tjs moins efficace...

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

54

La raison pour laquelle mutable n'est pas accepté en C est qu'une structure C doit être copiable par un memcpy. Si certains membres sont constants et d'autres non, alors on ne peut plus utiliser un memcpy d'une ancienne copie de la structure, on doit en plus mettre à jour tous les membres mutable.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

55

trifus
Je comprends absolument pas le pb, tu peux donner un exemple de code C où memcpy ne peut plus être utilisé à cause de la présence d'un mutable ?

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

56

const struct foo toto;
struct foo bar=toto;
abracadabra(&bar);
struct foo baz=bar; /* le compilateur ne peut pas utiliser toto en source à la place de bar ici, ce qui peut être une désoptimisation dans certains cas plus complexes */
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

57

Sauf que ce que tu oublies, c'est que justement lorsque la structure a un champ mutable, il n'y a pas de const dans le prototype de abracadabra, et le compilo est obligé de tout recopier (au lieu de recopier juste le champ mutable => gros appel de memcpy au lieu d'un simple move...)

Bien sûr, si abracadabra n'utilise jamais la partie mise en cache de foo, alors on peut mettre un 'const'. Mais l'idée du mutable est que les utilisations sans le membre mutable sont moins nombreuses que les utilisations avec ce membre-là (sinon, autant supprimer le const quand c'est nécessaire).

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

58

PpHd
: La conception du C++ est une daube en soie.

Une daube de luxe donc, en quelque sorte ? hehe
avatar
« Le bonheur, c'est une carte de bibliothèque ! » — The gostak distims the doshes.
Membrane fondatrice de la confrérie des artistes flous.
L'univers est-il un dodécaèdre de Poincaré ?
(``·\ powaaaaaaaaa ! #love#

59

./58: Lis la genese du C++ par son auteur. Ca vaut son pesant d'or...
./53.5: Comprends pas.
./53_sym; }.1: 1. struct ID { SYM *cached_sym; const char name[];}; SYM *sym(struct ID*id) { if (!id->cached_sym) id->cached_sym=Find(id->name); return id->cached
./53.3: Parce que tu crois encore que le C++ est efficace lol
./53.7: Pas si tu encapsules bien ta donnee. C'est a dire ne pas utiliser de classe.

60

5: Euh, y a rien à comprendre. Disons que "foobar *" est (en utilisation la notion des templates) un "ptr<foobar>", et tu peux modifier ce que désigne ptr<foobar> sans pour autant le modifier (donc *const ptr<foobar> n'est pas un "const foobar" mais un "foobar" tout court). C'est pareil pour "mutable foobar" aka "mut<foobar>" : tu peux modifier le contenu de "mut<foobar>" (i.e, la valeur de type foobar) sans modifier le contenant (le wrapper). En gros, l'implémentation inefficace de mut (qu'on est presque obligé d'utiliser en C) est vaguement équivalente à :
template<class T> mut {
  T* ptr;
public:
  mut() { ptr=new T; }
  ~mut() { delete ptr; }
  operator T&() const { return *T; }
};


1: Ne fais pas semblant de ne pas avoir lu la discussion précédente... C'est clairement plus efficace en mettant "const" qu'en ne le mettant jamais, puisque le compilo va louper plein d'optimisations dans la fonction appelante, avec ta méthode... Et tu vas devoir faire un memcpy dans l'exemple de Kevin au lieu de faire un move, etc...

3: Si tu te sers des facultés d'abstraction pour écrire du code bcp plus compact (utiliser des std::string au lieu de char*, par exemple), alors évidemment ton code sera moins efficace (mais aussi plus simple). Si tu veux écrire du code aussi efficace qu'en C, tu peux. Mais en plus, tu as les templates et les mutables qui te permettent de faire encore mieux. (tu peux te servir des templates comme d'un callback hyper puissant, par exemple; dans GTC 2.0 le parser utilise à fond les templates pour décrire les expressions avec priorités et ça permet de faire un truc hyper efficace)

7: C quoi la différence entre structure et classe selon toi?

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)