OVH Cloud OVH Cloud

C++ interface XML

16 réponses
Avatar
Ignace
Bonjour

Je désire réaliser une application en C++ qui manipule de gros fichiers de
configuration en XML (en local : pas un serveur).
Je travaille sur VS NET pour C++.

J'ai travaillé avec les DOM sous VB.
J'ai trouvé (beaucoup) d'exemples clairs en C#. Que j'ai compilé avec le NET
SDK.

Mon objectif est de réaliser du code C++

Pas moyen de porter sous C++ (includes, namespace...). Comment configurer
mon projet, quelles entêtes...
Un exemple ?

Est-il posible de porter du code C# en C++ ? Et utiliser xsd.exe ?

Quelles précautions à prendre pour que mon code soit le "plus multi plate
forme possible" (Linux et Unix).
(Isoler les accès bas niveau).


Merci

--
Ignace

6 réponses

1 2
Avatar
Ignace
"Ambassadeur Kosh" a écrit dans le message de
news:bu372g$dca$
> Il me semble que ça ne marche pas (erreur au link).

// Il s'agit du fichier projet principal pour le projet d'application VC++
// généré en utilisant un Assistant Application.

#include "stdafx.h"

#using <mscorlib.dll>
#using <system.xml.dll>

using namespace System;
using namespace System::Xml;

int _tmain()
{
System::Xml::XmlDocument *p = new System::Xml::XmlDocument() ;
p->LoadXml("<test/>") ;
Console::WriteLine(S"Hello World");
return 0;
}

ca compile, ça link, ça s'execute.
c'est un projet console C++ Managé de base.
si ça roule pas, c'est ton Vs qui pete un cable.





Merci, j'essaye.
Je pense que pa panne vient des identificateurs de portée ("." à la place de
":").
Quelles sont les options du Wizard d'application ?

> J'ai un problème : (VS .NET pour C++), la complétion ne fonctionne pas
bien.
pourtant, dans certaines "formes" d'écritures, elle marche à merveille.
il faudrait etre plus precis sur ce qui se passe.


> J'ai vaguement l'impression que mon IDE est dans les choux.
possible

> Oui, mais mon appli ne fait pas que ça : elle traite de la vidéo
image/image
> (après mes accès xml en initialisation). Le fait que j'utilise le


"managé"
> ne va t'il pas ralentir le reste de l'application (qui n'en a pas


besoin)
?

managé ne veux pas dire perfs pitoyables. si tu n'as pas confiance, sépare
les deux mondes. écrit toi une classe __gc d'interfacage, une classe


normale
pour l'implantation de l'autre. le beurre et l'argent du beurre.




Ce n'est pas l'ensemble du projet qui est "managé" ?

ensuite, amuses toi à comparer en rendant ta classe d'implantation __gc.
et utilises dedans des std::vector, std::toutcequetuveux, histoire de


voir.
tu peux aussi regarder du côté du code generé et comparer.

profite en pour t'appuyer sur un profiler. ça permet de ne pas tirer de
conclusions (trop) erronées sur ce qui pompe du temps, et ça peut


contribuer
à comprendre ce qui change, et ce qui ne change pas avec le concept des
classes managées (__gc)




> Franchement, le garbage collector, je sais m'en passer.

cette phrase a un parfum de testosterone :o)
les Cmens n'ont pas besoin d'objet, et d'un compilateur qui vérifie les
types, ils savent blabla blabla blabla etc.
bon, l'objet est infiniment superieur. considere que le gc est un apport
formel du même ordre.



Je suis convaincu pour l'objet et pour une structuration "forte".
Par contre, le garbage collector, pour l'instant, je trouve que c'est un
gadget dont je peux me passer.
Pire, je trouve ce concept un peu "anti structuré" : une "construction" doir
avoir un pendant : la "destruction". Même si c'est une opinion de mammouth.
Pour moi, j'ai remarqué que quand le développeur(se) "sait" détruire et
qu'il "laisse la mémoire dans l'état ou il la trouvée en entrant", c'est un
signe de robustesse du code.


> > l'unicité du langage ? bof. apprendre le C#, ça prend 20 minutes pour


un
> > gars qui connait l'Objet.
> Oui oui, c# semble très "sain". Un peu java sur les bords. Je ne m'en
plains
> pas

c'est clair. et avec ce qui va arriver (genre les generics), ça va devenir
de plus en plus interessant.




Je pense que le multi plate forme est un avantage (trolltech ?).
Le multi-langage, moins. Enfin, pour moi... Je vais peut être changer.

> le pointeur sur la structure de pointeurs qui identifient une table de
> fonctions qui retournent un pointeur (void).
> ...j'ai donné !

:o)

> Par contre le portage c#->c++ (non managé) ne me semble pas trivial...

bof. pourtant, ça me semble assez "direct" comme traduction. mais c'est
pareil, il faut exprimer ce que tu souhaites voir et ce que tu ne souhaite
pas voir comme bonnes propriétés dans le resultat. si c'est transformer


tout
seul des Algos NP en Algos P, je sais pas si on peut encore appeller ça du
portage.

mais pourquoi porter quand on peut utiliser directement ? qu'est ce qui


est
écrit en C# et qui ne te conviens pas ?



rien. Je trouve que c'est un peu propriétaire, c'est tout.
Si mono (que je découvre) fonctionne, mon argument ne veut plus rien dire.

tu as des fonctionalités en C# qui tournent trop lentement ? le but de la
manoeuvre, c'est que chacun écrit dans son langage preferé et hop,
interoperabilité. du multi culturel.




Je ne connais de C# que des tutoriels. Pas ses performances.

Je suppose que c'est du "super vb", sans le mot "basic" qui a fait vomir
tant de gourous.
Bref de l'interprété ou du semi inteprété genre pascal/delphi (PCode).
D'expérience, je trouve que de l'interprété bien écrit est beaucoup plus
efficace que du compilé natif bordelique.

pour ma part, je ne trouve pas le C# si lent que ça. j'ai des optims qui
tournent plein pot et qui sont écrites en C#. ça a certaines vertus, faire
des objets. par exemple celle de ne pas occuper la machine a faire des
copies en pagaille. mais bon, la encore, faut profiler au cas par cas.




quel profiler utilises tu ?


> Qu'est ce que "mono" ? (pardon si idiot)

c'est l'implantation sous Unix du Framework. dans l'avenir (s'il est
clément), le ciel sera radieu, et comme Java, les exe .Net d'une machine
tourneront sur une autre sans se soucier de rien. voila. Arnaud ou


Quentin
pourraient t'en dire un peu plus.

je te conseille vivement d'aller jetter un oeil sur le forum
microsoft.public.fr.dotnet.



j'y vais.


voila voila.




Merci
Avatar
Ambassadeur Kosh
>> managé ne veux pas dire perfs pitoyables. si tu n'as pas confiance,




sépare
les deux mondes. écrit toi une classe __gc d'interfacage, une classe
normale
pour l'implantation de l'autre. le beurre et l'argent du beurre.

Ce n'est pas l'ensemble du projet qui est "managé" ?





faut croire que non, sinon quel serait l'utilité du mot clé __gc qui
s'applique à une classe et non a un projet. ou alors je suis carrement passé
à côté du truc.
bon, tu vas me dire c'est peut être pas aussi simple que cela. et dans tous
les cas, je n'ai aucune preuve absolue que c'est pareil. tu ne peux que
constater empiriquement que les mesures de perfs sont tres voisines.

donc, pour être convaincu : construit toi un projet managé, et un autre non
managé, implante un algo de tueur qui utilise tous les bon mécanismes super
efficaces habituels : pointeurs,++, templates, inline, etc.. (sauf __gc
evidement) et compare les perfs. apres ça, tu pourras proceder aux
découpages que je t'ai proposé plus haut, et que je te recopie ici bas.


ensuite, amuses toi à comparer en rendant ta classe d'implantation __gc.
et utilises dedans des std::vector, std::toutcequetuveux, histoire de
voir.
tu peux aussi regarder du côté du code generé et comparer.

profite en pour t'appuyer sur un profiler. ça permet de ne pas tirer de
conclusions (trop) erronées sur ce qui pompe du temps, et ça peut
contribuer
à comprendre ce qui change, et ce qui ne change pas avec le concept des
classes managées (__gc)






au passage jette un oeil la dessus et navigue un peu :
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vcmxspec/html/vcManagedExtensionsSpec_16_2.asp


Je suis convaincu pour l'objet et pour une structuration "forte".



moi aussi.

Par contre, le garbage collector, pour l'instant, je trouve que c'est un
gadget dont je peux me passer.
Pire, je trouve ce concept un peu "anti structuré" : une "construction"


doir
avoir un pendant : la "destruction". Même si c'est une opinion de


mammouth.
Pour moi, j'ai remarqué que quand le développeur(se) "sait" détruire et
qu'il "laisse la mémoire dans l'état ou il la trouvée en entrant", c'est


un
signe de robustesse du code.



j'avais exactement cette vision la à la FAC, il y'a 4 ans, avec les mêmes
mots et les mêmes arguments.
manque d'objectivité, et reflet d'une peur face à un concept inconnu,
apprehension de ne pas maitriser, du changement...
ça montre aussi que tu as une visée machine implantation, et pas encore
assez specification/déclarative/fonctionelle.

depuis quand new alloue t'il de la mémoire, et delete remet le bloc a
disposition ? il y'a des caches MRU en pagailles, des mecanismes de
virtualisation, une traduction d'adresse logique intra processus en adresse
logique systeme, puis le systeme se demerde pour savoir si la page doit être
crée (on va pas reserver une page pour lire des 0 quand même), fournie, ou
alors recuperée dans le swap. il decide alors ou pas d'endormir le thread si
besoin. etc etc etc. ça fait long avant d'avoir une adresse physique.
pourtant tous ces mécanismes, tu t'appuies dessus. ça s'appelle le systeme.
et ça ne te traumatise pas toute la journée de savoir qu'un bloc de mémoire
que tu viens de deleter ne te sera pas forcément proposé directement au
prochain new.

l'efficacité ? il a été montré qu'un garbage collector ameliore l'efficacité
d'un processus. eh oui, tirer la chasse d'eau une fois prends moins de temps
que tirer la chasse d'eau un petit peu des millions de fois. le cout de
préparation du paquet à balancer est moindre au total, parait il. en clair,
c'est rentable.

le biais sur la conception ? bof... mais nous discuterons d'un certain
christophe qui pensait que faire des struct etait preferable à faire des
class, cause localité de variable au sein d'une boucle, et volonté de
liberer le paquet de suite, histoire de respecter une forme de symetrie et
la croyance dont tu parles... il a été bien surpris, christophe.

pour faire une comparaison, écrire les delete, c'est comme écrire du code
toutes les 3 lignes pour provoquer soit même le swap vers un autre
processus. ça fait perdre du temps à l'execution, ça prend une place
monstrueuse, ça donne au code une charge supplémentaire, et
conceptuellement, l'idée est naze. mieux vaut laisser un agent systeme faire
le taf. ça existe déja pour les pages et le swap,

le typage fort n'est pas tout...

Je pense que le multi plate forme est un avantage (trolltech ?).
Le multi-langage, moins. Enfin, pour moi... Je vais peut être changer.



faire en sorte que plusieurs membres avec une culture et un vehicule
culturel différent puissent cooperer, et réutiliser le travail des autres,
c'est pas mal.
et finalement, aubout du compte, il n'y a qu'un seul langage.

mais pourquoi porter quand on peut utiliser directement ? qu'est ce qui




est
écrit en C# et qui ne te conviens pas ?


rien. Je trouve que c'est un peu propriétaire, c'est tout.
Si mono (que je découvre) fonctionne, mon argument ne veut plus rien dire.



maintenant, Utopie ou pas, va t'en savoir...

Je ne connais de C# que des tutoriels. Pas ses performances.



quelques tests s'imposent donc.

Je suppose que c'est du "super vb", sans le mot "basic" qui a fait vomir
tant de gourous.
Bref de l'interprété ou du semi inteprété genre pascal/delphi (PCode).



aie. je craignais d'entendre ça :o)

D'expérience, je trouve que de l'interprété bien écrit est beaucoup plus
efficace que du compilé natif bordelique.



oui. c'est clair qu'entre un algo NP en natif et un algo P en interpeté, y a
pas photo.
et quand on voit les bonnes propriétés du code safe, ça vaut le coup
d'évoluer un peu.


quel profiler utilises tu ?


chsai plus. je te redirai.

je te conseille vivement d'aller jetter un oeil sur le forum
microsoft.public.fr.dotnet.


j'y vais.



euuh, fait gaffe à la façon dont tu poseras tes questions. y'a un troll qui
sevit. il a declaré la guerre à la moitié des participants, et il est en
instance de le faire avec l'autre moitité. c'est assez penible.

A+
Avatar
Arnaud Debaene
Ambassadeur Kosh wrote:

managé ne veux pas dire perfs pitoyables. si tu n'as pas confiance,




sépare
les deux mondes. écrit toi une classe __gc d'interfacage, une classe
normale
pour l'implantation de l'autre. le beurre et l'argent du beurre.







Mauvais plan sur la comète! Le marshalling entre les couches managées et non
managées est très inefficace! En plus, le "__pinnage" des objets dégrade
significativement la vitesse d'exécution du GC. Ajoutes à cela la syntaxe
ignoble des extensions C++ managées (exemple à 2 balles : comment tu
déclares une fonction qui renvoie un tableau (System.Array) en C++
managé? ), et tu te rends comptes que le C++ managé est très bien pour
interfacer .NET avec du code existant, mais que ce n'est AMHA pas une bonne
idée de s'appuyer dessus pour de nouveaux développements.

bon, tu vas me dire c'est peut être pas aussi simple que cela. et
dans tous
les cas, je n'ai aucune preuve absolue que c'est pareil. tu ne peux
que
constater empiriquement que les mesures de perfs sont tres voisines.



Deux petites remarques supplémentaires sur cet aspect :
- Actuellement, le compilateur C++ managé optimise mieux et d'avantage le
bytecode qu'il produit que le compilateur C#. Si les perfs sont vraiement
capitales - ce qui est rare - ça peut être à prendre en compte.
- Le compilateur JIT actuel n'optimise absolument pas pour le processeur
cible. Théoriquement, il est possible de faire un compilateur JIT qui
optimise le code pour la machine d'exécution (je suppose - j'espère - que
des gens bossent dessus chez M$) mais ce n'est pas le cas actuellement. Cet
arguement ne tient donc pas pour l'instant. De toute façon, il est très
difficile de faire des optimisations très poussées dans la compilation JIT
tout en gardant des temps de réponses acceptables au démarrage de
l'application : le compilateur JIT doit être rapide, donc relativement
simple.

ensuite, amuses toi à comparer en rendant ta classe d'implantation
__gc.
et utilises dedans des std::vector, std::toutcequetuveux, histoire
de
voir.






Mais qu'est ce qu'elle t'as fait la STL? Elle t'a traumatisée quand tu étais
petit ? ;-) Rien que pour la "type safety" qu'elle offre, je préfère de loin
la STL!

<snip>

Je suis convaincu pour l'objet et pour une structuration "forte".



moi aussi.



Je mettrais cependant un bémol : l'objet c'est très bien et même
indispensable, mais ca ne couvre pas tous les besoins et ce n'est pas la
solution universelle (philosophiquement, je me méfie toujours des solutions
universelles ;-) Et le problème du .NET, c'est qu'il ne t'offre pas d'autres
paradigmes de programmation et restreint donc tes choix. C++ est
multi-paradigme et laisse plus de liberté (y compris celle de se tirer dans
le pied, c'est vrai).
A titre d'exemple, la programmation générique est en plein essort dans le
monde du C++ et on commence à peine à découvrir les possibilités qu'elle
offre - et non, les génériques de C# 2.0 ne permettent pas de faire de la
programmation générique, loin s'en faut!

<snip>
l'efficacité ? il a été montré qu'un garbage collector ameliore
l'efficacité
d'un processus. eh oui, tirer la chasse d'eau une fois prends moins
de temps
que tirer la chasse d'eau un petit peu des millions de fois. le cout
de
préparation du paquet à balancer est moindre au total, parait il. en
clair,
c'est rentable.



Non, c'est faux. Tout ce qui a été montré, c'est que avec certains schémas
d'allocations spécifiques, un GC était plus efficace qu'une gestion
classique de la mémoire. Le problème de tous ces tests de "pour" ou "contre"
les GC, c'est qu'ils sont systématiquement faits avec des schémas
d'allocations assez artificiels (du genre "j'alloue en une seule fois x
objets de taille y, je les utilises et je les libères un par un,
dans l'ordre inverdse de celui d'allocation", ou d'autres variantes). Le
problème, c'est que dans les applications réelles, les schémas d'allocation
sont beaucoup moins prévisibles : on alloue généralement des blocs de taille
variable sans ordre particulier ni symétrie dans l'ordre des allocations /
désallocations, et il est beaucoup plus difficile de faire des tests de
performances dans ces conditions.

Tout ce qu'on peut dire de manière fiable et sure en comparant le GC .NET et
un mécanisme d'allocation classique comme celui de la CRT de Visual, c'est
que :
- Avec un GC, l'allocation est plus rapide (on incrémente un compteur au
lieu de parcourir une liste chainée).
- Avec un GC, la désallocation est moins rapide (il faut parcourir
l'arborescence des références au lieu d'insérer un maillon dans une liste
chainée, plus la surcharge système de l'arrêt/synchronisation de tous les
threads du processus)
- Avec une gestion classique, il y a risque (évitable si on sait ce qu'on
fait) de faire beaucoup de copies inutiles d'objets. Ceci dit, le GC quand
il libère la mémoire fait exactement la même chose - des copies ou plus
précisémment des déplacements d'objets.
- Avec un GC, les désallocations/destructions sont faites par gros blocs
(quand le GC tourne). En soi, c'est difficile de dire si c'est plus ou moins
efficace, mais le défaut c'est qu'on risque d'avoir des "pauses" dans
l'exécution du programme (pendant que le GC tourne, tous les threads de
l'appli sont bloqués), alors qu'avec des destructions tout au long du fil du
programme, le temps passé dans ces destructions est "lissé" sur toute la
durée d'exécution. C'est typiquement très visible en Java. Je dois
reconnaitre que c'est nettement moins perceptible en .NET : je suppose que
c'est lié essentiellement au mécanisme générationnel du GC .NET. Dans tous
les cas, ca rend bien sûr les GC inapliquables si on a des contraintes
temprs réel fortes - ce qui est rare j'en conviens.

Ceci dit, indépendamment de toutes ces considérations d'accro au
performances qui n'ont généralement pas beaucoup d'intérêt pratique, le GC
tel que proposé en .NET présente à mon avis 2 énormes défauts :

- l'idiome RAII (Ressource Acquisition Is Initialization) est innapliquable
parce qu'il n'y a pas de destructeurs synchrones. Quand je dis ressource
dans ce contexte, je ne parle pas de mémoire mais d'une ressource logique
qu'on *doit* libérer manuellement. Exemple typique : un smart-pointer tenant
une référence sur un objet COM avec gestion du compteur de références
(appels à AddRef/Release), ou bien une classe encapsulant l'accès exclusif à
un périphérique (un port série, une carte d'acquisition, ...) : c'est
infaisable en C#. A ce sujet, il parait que dans Whidbey, le C++ managé
offrira des destructeurs appelés de manière synchrone : là on profitera du
meilleur des 2 mondes.

- la séparation "les classes complexes sont allouées sur le tas et gérées
par le GC et les types primitifs et les objets simples (struct) sont alloués
sur la pile" est ridicule et n'a pas de sens du point de vue de la
conception objet pure. On peut très bien avoir besoin localement dans une
fonction d'un objet complexe (de par son arbre d'héritage, sa taille ou
autre), et il n'y a pas de raison de ne pas pouvoir l'allouer sur la pile.
.NET offre déjà une amélioration de ce point de vue par rapport à Java grâce
aux structs et au boxing/unboxing automatique, mais on n' a pas encore la
souplesse du C++ (au fait, toi qui te plaint des copies cachées en C++, le
boxing/unboxing entraine des copies de l'objet!)

<snip>

pour faire une comparaison, écrire les delete, c'est comme écrire du
code
toutes les 3 lignes pour provoquer soit même le swap vers un autre
processus. ça fait perdre du temps à l'execution, ça prend une place
monstrueuse, ça donne au code une charge supplémentaire, et
conceptuellement, l'idée est naze. mieux vaut laisser un agent
systeme faire
le taf. ça existe déja pour les pages et le swap,


??? tu peux expliquer en quoi écrire un delete ressemble à "swapper vers un
autre processus" (ce qui ne veut rien dire en soi...) ? Je te rappelles
qu'écrire un delete, ce n'est pas que libérer de la mémoire, c'est avant
tout appeler un destructeur (logiquement, c'est bien plus important).

Au passage, dans du code C++ *bien écrit*, il n'y a pas (ou très peu) de
delete. On utilise RAII ! Je vois (et ponds) régulièrement du code C++ de
plus de 10000 ligne sans un seul delete dans le code utilisateir.

En ce qui concerne la taille "monstrueuse" (tu as des chiffres?) du code de
destruction des objets généré par le C++, c'est vrai que ce code prend de la
place, mais :
- le GC aussi prend de la place :-)
- le code de destructions C++ fait partie du déroulement normal du programme
et bénéficie donc des effets de cache et de pipeline sur le processeur. Par
contre, quand le GC se déclenche, tu es bon à tous les coups pour vider le
pipeline (tu changes de thread) et le code du GC ne respecte absolument pas
la localité de référence (il accède à des zones mémoires très diparates dans
un temps très court), autrement dit le cache processeur est très inefficace
pendant ce temps.

Arnaud
Avatar
Ambassadeur Kosh
> Mauvais plan sur la comète! Le marshalling entre les couches
managées et non managées est très inefficace! En plus, ...
<snip/> de nouveaux développements.



bof. ce n'est pas l'experience que j'en ai. evidement, si tu appelles un
milliards de fois une fonction atomique, la rentabilité va être bien
compromise. mais bon c'est du même genre que de parler de
l'efficactié de virtual avec une fonction void Test::f(int &i){ i++ ; }

je pense bien que pour faire de la 3D plein pot, c'est pas l'idéal.
mais pour mes petits besoins à moi, c'est pas si mal...

donc, il verra, il profilera, et il decidera...

Deux petites remarques supplémentaires sur cet aspect :
- Actuellement, le compilateur C++ managé optimise mieux <snip/>



oui, il parait.

- Le compilateur JIT actuel n'optimise absolument pas pour le processeur
cible. Théoriquement, il est possible de faire un compilateur JIT qui
optimise le code pour la machine d'exécution <snip/>.



c'est uniquement fondé sur le bon sens, mais autant
la transformation C#->PCode a de l'importance, autant PCode->Machine
n'en a pas trop, vu le faible niveau d'abstraction du PCode.
quand je vois comment un HP9000 optimise les branchements à la volée,
les pipelines pour le code, la vitesse à laquelle le materiel évolue et tout
et tout, ben je me dis que tout ça n'a pas grande importance.

Mais qu'est ce qu'elle t'as fait la STL? Elle t'a traumatisée quand tu
étais petit ? ;-) Rien que pour la "type safety" qu'elle offre, je préfère
de loin la STL!



ben non pourtant... "vote stl for president".
c'était juste au cas ou il se serait imaginé que managé changeait le langage
accepté ou comprometait gravement le lot commun du developpeur.

Je mettrais cependant un bémol : l'objet c'est très bien et même
indispensable, mais ca ne couvre pas tous les besoins et ce n'est pas la
solution universelle (philosophiquement, je me méfie toujours des
solutions universelles ;-) Et le problème du .NET, c'est qu'il ne t'offre
pas d'autres paradigmes de programmation et restreint donc tes choix.
C++ est multi-paradigme et laisse plus de liberté (y compris celle de se
tirer dans le pied, c'est vrai).



j'ai déja entendu un certain trollou dire ça :o)

A titre d'exemple, la programmation générique est en plein essort dans le
monde du C++ et on commence à peine à découvrir les possibilités qu'elle
offre - et non, les génériques de C# 2.0 ne permettent pas de faire de la
programmation générique, loin s'en faut!



tu troll grave la.
List[E], c'est quoi si c'est pas de la genericité ?

bon, poussons le raisonnement. definissons une classe ArrayN<n> qui est un
tableau à n dimension. à ce jour je ne connais aucun langage qui sait
définir ArrayN<n> en fonction de ArrayN<n-1> et de ArrayN<0>. pourtant c'est
de la genericité ça. donc "les génériques de C++ ne permettent pas de faire
de la programmation générique, loin s'en faut".

Non, c'est faux.


Non, c'est vrai, blblblblblblbl :o)

Tout ce qui a été montré, c'est que <snip/>
- Avec un GC, l'allocation est plus rapide (on incrémente un compteur au
lieu de parcourir une liste chainée).


ok.

- Avec un GC, la désallocation est moins rapide (il faut parcourir
l'arborescence des références au lieu d'insérer un maillon dans une liste
chainée, plus la surcharge système de l'arrêt/synchronisation de tous les
threads du processus)



ça c'est une vision locale. mais globalement c'est rentable, même si
localement, ça peut couter plus cher.

- Avec une gestion classique, <snip/>
mais le défaut c'est qu'on risque
d'avoir des "pauses" dans l'exécution du programme (pendant que le
GC tourne, tous les threads de l'appli sont bloqués), alors qu'avec
des destructions tout au long du fil du
programme, le temps passé dans ces destructions est "lissé" sur toute la
durée d'exécution.



le concept de GC n'implique pas d'arreter tous les threads. cette
implantation le fait. c'est un choix. tant pis.

le risque de pause, je le mettait comme argument numero 1
de mes revendications trolleennes à la FAC. mais c'est du flan.

sur une execution, il y a du temps ou la machine ne branle rien.
pourquoi lisser le temps de destruction alors qu'on peut utiliser
le temps mort pour ça.

voila le rapprochement avec l'allocation de pages mémoires
du systeme. on a déja la "meme" fonctionalité sous jacente
dans le systeme et que la memoire virtuelle est vue comme
un avantage et non comme un inconvenient.

on a ce qu'on merite. si on est en quantité critique de
resources, on est mal pour les perfs. si on est en
surabondance, ce qui peut se faire de nos jours, un
mécanisme comme celui ci va être des plus efficaces.

C'est typiquement très visible en Java. Je dois
reconnaitre que c'est nettement moins perceptible en .NET : je suppose que
c'est lié essentiellement au mécanisme générationnel du GC .NET. Dans tous
les cas, ca rend bien sûr les GC inapliquables si on a des contraintes
temprs réel fortes - ce qui est rare j'en conviens.



j'en conviens égallement.

Ceci dit, indépendamment de toutes ces considérations d'accro au
performances qui n'ont généralement pas beaucoup d'intérêt pratique, le GC
tel que proposé en .NET présente à mon avis 2 énormes défauts :



- l'idiome RAII (Ressource Acquisition Is Initialization) est
innapliquable<snip/>



prenons les streams. la fermeture du flux ne se fait pas de maniere
synchrone à la destruction puisque le destructeur est appellé quand
la machine a le temps. donc la fermeture est mise dans Close(), qu'on
appelle au moment souhaité. est-ce une bonne chose de vouloir
bourrer des fonctionalités dans le destructeur ? cela a t'il une utilité
réelle ? quelles bonnes propriétés/avantages cela est il censé
apporter ? a t'on vraiment besoin d'un tel mécanisme ? pourquoi ?

- la séparation "les classes complexes sont allouées sur le tas et gérées
par le GC et les types primitifs et les objets simples (struct) sont
alloués sur la pile" est ridicule et n'a pas de sens du point de vue de la
conception objet pure. On peut très bien avoir besoin localement dans une
fonction d'un objet complexe (de par son arbre d'héritage, sa taille ou
autre), et il n'y a pas de raison de ne pas pouvoir l'allouer sur la pile.
.NET offre déjà une amélioration de ce point de vue par rapport à Java
grâce aux structs et au boxing/unboxing automatique, mais on n' a pas
encore la souplesse du C++ (au fait, toi qui te plaint des copies cachées
en C++, le > boxing/unboxing entraine des copies de l'objet!)



bof. moi je m'en fous que l'objet soit alloué sur la pile ou sur le tas.
on donne la sémantique struct ou class à son objet selon le besoin
sémantique. c'est quand même un drole de hasard qu'on trouve le
même concept en Eiffel (expanded). et l'exemple de christophe montre
qu'utiliser un struct ne sert pas à grand chose (je pense que c'est
ça que tu appelles boxing unboxing). je pense même qu'un jour,
le compilateur sera doté d'un mécanisme de decision qui choisira
localement entre struct ou class à la compilation.

donc, présenter le concept struct/class comme un inconvenient, bof...

??? tu peux expliquer en quoi écrire un delete ressemble à "swapper vers
un> autre processus" (ce qui ne veut rien dire en soi...) ? Je te


rappelles
qu'écrire un delete, ce n'est pas que libérer de la mémoire, c'est avant
tout appeler un destructeur (logiquement, c'est bien plus important).



tout est déja dit. quand je dis swapper vers un autre processus, je parle
du systeme multitache. et un destructeur, ça sert à liberer des resources.
confier des taches autres que ça au destructeur, bof...

Au passage, dans du code C++ *bien écrit*, il n'y a pas (ou très peu) de
delete.



c'est clair. une application qui fait de l'allocation à robinet ouvert et
passe un temps conséquent la dessus necessite qu'on s'interroge.

On utilise RAII ! Je vois (et ponds) régulièrement du code C++ de
plus de 10000 ligne sans un seul delete dans le code utilisateir.
En ce qui concerne la taille "monstrueuse" (tu as des chiffres?) du code
de destruction des objets généré par le C++, c'est vrai que ce code prend


de
la place, mais :



il ne s'agit pas de cela du tout. je t'invite à relire. il s'agit
d'opportunité du moment, et de complexité. je t'accorde
que ce n'est pas evident à saisir. le type de mon objet
est decidé au milieu d'un calcul, puis mon objet se balade,
et decider à un autre endroit du code si l'objet est encore
utilisé ou pas est extrement chiant. le GC est bon la.

- le GC aussi prend de la place :-)



comme tout.

- le code de destructions C++ fait partie du déroulement normal du
programme et bénéficie donc des effets de cache et de pipeline sur le
processeur. Par contre, quand le GC se déclenche, tu es bon à tous
les coups pour vider le <snip/>



le GC sera un jour aussi un "concept materiel".
je ne prend pas beaucoup de risques en affirmant cela.
donc, condamner le principe du GC à cause d'une implantation du moment...
bof

Arnaud, je ne sais pas ce qu'il y a mais sur le coup la, et sur tes posts
precedents,
je trouve que tu as bouffé du troll...
Avatar
Arnaud Debaene
Ambassadeur Kosh wrote:

- Le compilateur JIT actuel n'optimise absolument pas pour le
processeur cible. Théoriquement, il est possible de faire un
compilateur JIT qui optimise le code pour la machine d'exécution
<snip/>.



c'est uniquement fondé sur le bon sens, mais autant
la transformation C#->PCode a de l'importance, autant PCode->Machine
n'en a pas trop, vu le faible niveau d'abstraction du PCode.
quand je vois comment un HP9000 optimise les branchements à la volée,
les pipelines pour le code, la vitesse à laquelle le materiel évolue
et tout et tout, ben je me dis que tout ça n'a pas grande importance.



Je disais juste ça par rapport au fait que l'argument "le compilateur JIT
optimisateur de la mort qui tue pour ton processeur particulier à toi" est
souvent ressorti par les zélotes de .NET alors que c'est un argument
fallacieux.

Je mettrais cependant un bémol : l'objet c'est très bien et même
indispensable, mais ca ne couvre pas tous les besoins et ce n'est
pas la solution universelle (philosophiquement, je me méfie toujours
des solutions universelles ;-) Et le problème du .NET, c'est qu'il
ne t'offre pas d'autres paradigmes de programmation et restreint
donc tes choix.
C++ est multi-paradigme et laisse plus de liberté (y compris celle
de se tirer dans le pied, c'est vrai).



j'ai déja entendu un certain trollou dire ça :o)


L'histoire de la balle dans le pied, c'est une citation de Stroustrup.
Maintenant, si tu veux considérer que Stroustrup est un troll, je te laisse
la responsabilité de tes opinions! ;-)

A titre d'exemple, la programmation générique est en plein essort
dans le monde du C++ et on commence à peine à découvrir les
possibilités qu'elle offre - et non, les génériques de C# 2.0 ne
permettent pas de faire de la programmation générique, loin s'en
faut!



tu troll grave la.
List[E], c'est quoi si c'est pas de la genericité ?



La *programmation* générique, comme toute programmation, doit remplir au
minimum les impératifs d'une machine de Turing. Parmi les éléments les plus
notoires d'une machine de Turing, il y a la capacité de branchement
conditionnel (if ... else). Avec les templates C++, cette fonction est
remplie par la spécialisation partielle de template. Il n'y a pas
d'équivalent avec les génériques C#. Les templates C++ forment u langage
fonctionnel Turing-complete executé au moment de la compilation.

Comme c'est un sujet HS et trop long pour être abordé en détail ici, je
t'invite à te pencher sur le bouquin "Modern C++ Design" et sur la
bibliothèque associée, Loki, si tu veux plus de détails sur ce sujet. C'est
le seul bouqin en informatique qui m'as véritablement mis le c* part terre
récemment.

bon, poussons le raisonnement. definissons une classe ArrayN<n> qui
est un tableau à n dimension. à ce jour je ne connais aucun langage
qui sait définir ArrayN<n> en fonction de ArrayN<n-1> et de
ArrayN<0>. pourtant c'est de la genericité ça. donc "les génériques
de C++ ne permettent pas de faire de la programmation générique, loin
s'en faut".


C'est possible, bien qu'inutilement complexe.
Dans le même genre en plus simple, les templates C++ permettent de définir
une fonction factorielle exactement sur le même principe. C'est une valeur
entièrement calculée à la compilation et dont le temps d'exécution est donc
constant :

<exemple categorie="bateau">
template <int N> struct factoriel
{
enum { value = N * factoriel<N-1>::value};
};

template<> struct factoriel <1>
{
enum { value = 1};
};

int main
{
std::cout<<factoriel<15>::value<<std;; endl; //valeur entièrement
calculée à la compilation.
}
</exemple>


- Avec un GC, la désallocation est moins rapide (il faut parcourir
l'arborescence des références au lieu d'insérer un maillon dans une
liste chainée, plus la surcharge système de l'arrêt/synchronisation
de tous les threads du processus)



ça c'est une vision locale. mais globalement c'est rentable, même si
localement, ça peut couter plus cher.


Tu pourrais démontrer cette assertion par un calcul de complexité, même
qualitatif?

- Avec une gestion classique, <snip/>
mais le défaut c'est qu'on risque
d'avoir des "pauses" dans l'exécution du programme (pendant que le
GC tourne, tous les threads de l'appli sont bloqués), alors qu'avec
des destructions tout au long du fil du
programme, le temps passé dans ces destructions est "lissé" sur
toute la durée d'exécution.



le concept de GC n'implique pas d'arreter tous les threads. cette
implantation le fait. c'est un choix. tant pis.


Tu as déjà vu une implémentation de GC qui ferait autrement? J'ai beau me
torturer l'esprit, je ne vois pas comment c'est conceptuelement faisable vu
que le GC va déplacer en mémoire des objets susceptibles d'êtres manipulés
en même temps par les threads de l'application.


le risque de pause, je le mettait comme argument numero 1
de mes revendications trolleennes à la FAC. mais c'est du flan.

sur une execution, il y a du temps ou la machine ne branle rien.
pourquoi lisser le temps de destruction alors qu'on peut utiliser
le temps mort pour ça.


Je repose la question : as-tu déjà vu une implémentation de GC qui fasse
comme çà? Toutes celles que je connais se déclenchent quand elles détectent
que le système est en passe de manquer de mémoire, ou bien à intervalle
régulier.


- l'idiome RAII (Ressource Acquisition Is Initialization) est
innapliquable<snip/>



prenons les streams. la fermeture du flux ne se fait pas de maniere
synchrone à la destruction puisque le destructeur est appellé quand
la machine a le temps. donc la fermeture est mise dans Close(), qu'on
appelle au moment souhaité. est-ce une bonne chose de vouloir
bourrer des fonctionalités dans le destructeur ? cela a t'il une
utilité réelle ? quelles bonnes propriétés/avantages cela est il censé
apporter ? a t'on vraiment besoin d'un tel mécanisme ? pourquoi ?



- Si la ressource est critique et doit être libérée le plus rapidement
possible (un périphérique matériel par exemple), alors oui c'est utile.

- Plus important, pour écrire du code "exception safe", la seule façon de
faire en C# est de parsemer son code de finally (ou de using - ce qui
revient au même ) dans tous les coins.
Remarque : pour que du code soit "exception-safe", il faut qu'en cas
d'exception, le code de "nettoyage" et de remise en état stable de tes
données soit effectué de manière synchrone par rapport au "stack unwinding,
et pas quand le GC décide de se déclencher. Par exemple, si l'écriture dans
un fichier échoue, il faut soit remettre le fichier dans son état antérieur
soit effacer le fichier, et ce avant de faire quoi que ce soit d'autre dans
ton programme, vu que le fichier est potentiellement corrompu et contient
n'importe quoi.
Utiliser des finally, ca marche certes, mais ca alourdis énormément le code
et le rend difficilement lisible et maintenable. Au contraire, l'idiome RAII
permet d'avoir un code particulièrment léger et naturel, où l'algorithmie ne
s'encombre de gestion lourdingue des ressources.

- la séparation "les classes complexes sont allouées sur le tas et
gérées par le GC et les types primitifs et les objets simples
(struct) sont alloués sur la pile" est ridicule et n'a pas de sens
du point de vue de la conception objet pure. On peut très bien avoir
besoin localement dans une fonction d'un objet complexe (de par son
arbre d'héritage, sa taille ou autre), et il n'y a pas de raison de
ne pas pouvoir l'allouer sur la pile. .NET offre déjà une
amélioration de ce point de vue par rapport à Java grâce aux structs
et au boxing/unboxing automatique, mais on n' a pas encore la
souplesse du C++ (au fait, toi qui te plaint des copies cachées en
C++, le > boxing/unboxing entraine des copies de l'objet!)



bof. moi je m'en fous que l'objet soit alloué sur la pile ou sur le
tas.


Y compris par rapport au maintien de la cohérence de tes données en cas
d'exception?

on donne la sémantique struct ou class à son objet selon le besoin
sémantique.


Ben justement, si je veux définir un objet à comportement polymorphique (ou
contenant un objet polymorphiqe pour être plus réaliste) mais à durée de vie
automatique, je fais comment?

c'est quand même un drole de hasard qu'on trouve le
même concept en Eiffel (expanded). et l'exemple de christophe montre
qu'utiliser un struct ne sert pas à grand chose


Quel exemple de Christophe? Je n'ai pas la référence dont tu parles.

(je pense que c'est
ça que tu appelles boxing unboxing).


Pour faire simple, le boxing/unboxing, c'est la capacité de C# de
transformer une "value type" en object :
int i 3;
object o =i; //ici, une copie de i est réalisée sur le tas.

je pense même qu'un jour,
le compilateur sera doté d'un mécanisme de decision qui choisira
localement entre struct ou class à la compilation.


Fichtre..., on parle bien du C# là? Parce qu'alors il faudra revoir les
définitions de class et struct dans ce langage vu que ces deux concepts ne
permettent pas de faire la même chose! Entre autres différences :
- une struct ne peut que hériter d'object et implémenter des interfaces (pas
d'héritage d'implémentation).
- une struct ne peut pas définir de constructeur par copie (il est
implicite).
- une struct ne peut pas avoir de destructeur.
- le plus important : la class a une sémantique de référence, la struct de
valeur (j'enfonce des portes ouvertes là...) : je ne vois pas comment un
compilateur pourras jamais deviner la *sémantique* d'un type si te ne la lui
explicite pas syntaxiquement dans le langage. En C#, on lui explique en
utilisant struct ou class, en C++ on le lui explique indirectement par le
contenu des constructeur par copie et opérateurs d'assignement.

??? tu peux expliquer en quoi écrire un delete ressemble à "swapper
vers un> autre processus" (ce qui ne veut rien dire en soi...) ? Je
te rappelles qu'écrire un delete, ce n'est pas que libérer de la
mémoire, c'est avant tout appeler un destructeur (logiquement, c'est
bien plus important).



tout est déja dit. quand je dis swapper vers un autre processus, je
parle du systeme multitache. et un destructeur, ça sert à liberer des
resources. confier des taches autres que ça au destructeur, bof...


Désolé, je dois être obtus mais je ne vois toujouts pas ce que la gestion du
multitâche préemptif (s'il s'agit bien de çà) à a voir avec le mécanisme de
gestion des ressources d'un langage.

Au passage, dans du code C++ *bien écrit*, il n'y a pas (ou très
peu) de delete.



c'est clair. une application qui fait de l'allocation à robinet
ouvert et passe un temps conséquent la dessus necessite qu'on
s'interroge.


Non, tu ne m'as pas compris (au passage, un programme .NET va avoir tendance
à faire beaucoup plus d'allocations mémoire qu'un programme C++). : Je parle
du fait qu'en C++ on s'arrange pour que le langage fasse lui même le ménage
(via les destructeurs) pour les ressoures qu'on alloue et ce de manière
synchrone.

En ce qui concerne la taille "monstrueuse" (tu as des chiffres?) du
code de destruction des objets généré par le C++, c'est vrai que ce
code prend de la place, mais :



il ne s'agit pas de cela du tout. je t'invite à relire.



Je relis donc :
pour faire une comparaison, écrire les delete, c'est comme écrire du
code
toutes les 3 lignes pour provoquer soit même le swap vers un autre
processus. ça fait perdre du temps à l'execution, ça prend une place
monstrueuse, ça donne au code une charge supplémentaire, et
conceptuellement, l'idée est naze.



Pourrais-tu m'expliquer ton parallélisme, parce que j'avoue que je ne vois
toujours pas le rapport entre le swap d'un thread à l'autre (qui sert à
faire plusieurs tâches en "pseudo-parallèle" sur un processeur) et la
politique de libération des ressources d'un programme donné.

il s'agit
d'opportunité du moment, et de complexité. je t'accorde
que ce n'est pas evident à saisir.


Non, c'est le moins qu'on puiss dire, essaie de clarifier!

le type de mon objet
est decidé au milieu d'un calcul,


Argh, déjà j'ai du mal là! Tu décides du *type* d'un objet d'après un calcul
réalisé au runtime? Le seul cas où il est légitime de faire çà, c'est dans
une fabrique d'objets, quel que soit le langage.

puis mon objet se balade,


Voui, si ca lui fait plaisir...

et decider à un autre endroit du code si l'objet est encore
utilisé ou pas est extrement chiant.


Si tu utilises intelligemmment les règles de durée de vie du C++ et que tu
as du code résonnablement bien structuré, l'objet est détruit (et ses
ressources libérées), lorsqu'il quitte son "scope" de visibilité.

- le code de destructions C++ fait partie du déroulement normal du
programme et bénéficie donc des effets de cache et de pipeline sur le
processeur. Par contre, quand le GC se déclenche, tu es bon à tous
les coups pour vider le <snip/>



le GC sera un jour aussi un "concept materiel".
je ne prend pas beaucoup de risques en affirmant cela.


Ah bon? Ca ne me semble pas trop scientifique comme argument çà, mais enfin
bon pourquoi pa... Moi ce qui m'intéresse (et surtout mon patron!), c'est
*aujourd'hui* de savoir l'impact du choix de C# pour faire telle ou telle
chose, pas dans un futur hypothétique.

Arnaud, je ne sais pas ce qu'il y a mais sur le coup la, et sur tes
posts precedents,
je trouve que tu as bouffé du troll...


Fichtre, d'autres ont eu la même impression là??? Va peut être falloir que
je me soigne alors! ;-)

Sérieusement, ca ne serait pas toi qui ferait dans la paranoia trollesque et
manquerait un peu d'objectivité dans tes jugements? .NET a d'immenses
qualités (la richesse et la qualité de la BC et du framework, la simplicité
de codage, la gestion des assembly et la fin du DLL-hell, ...), mais tout
MVP que je suis, ca ne m'empêche pas de rester critique malgré tout!

Arnaud
Avatar
Ambassadeur Kosh
> Je disais juste ça par rapport au fait que l'argument "le compilateur JIT
optimisateur de la mort qui tue pour ton processeur particulier à toi" est
souvent ressorti par les zélotes de .NET alors que c'est un argument
fallacieux.



c'est clair.



j'ai déja entendu un certain trollou dire ça :o)


L'histoire de la balle dans le pied, c'est une citation de Stroustrup.
Maintenant, si tu veux considérer que Stroustrup est un troll, je te
laisse la responsabilité de tes opinions! ;-)



:o)



List[E], c'est quoi si c'est pas de la genericité ?


La *programmation* générique, comme toute programmation, doit remplir au
minimum <snip/>



ok. ceci dit, je ne pensais pas qu' "on" en demanderait autant à de la
genericité. j'en suis resté à ce qui a été fait avec la stl.



Comme c'est un sujet HS et trop long pour être abordé en détail ici, je
t'invite à te pencher sur le bouquin "Modern C++ Design" et sur la
bibliothèque associée, Loki, si tu veux plus de détails sur ce sujet.
C'est le seul bouqin en informatique qui m'as véritablement mis le c*
part terre récemment.



avec joie. je ne connais pas Loki. et ça fait "longtemps" que je n'ai pas eu
l'occasion de lire un bon bouquin sur C++. décidement, Adison Wesley a
le monopole des bouqins interessants.



Dans le même genre en plus simple, les templates C++ permettent de définir
une fonction factorielle exactement sur le même principe. C'est une valeur
entièrement calculée à la compilation et dont le temps d'exécution est
donc constant :



eh ben, toi qui dit que l'objet ne fait pas tout... en "types", on montre
qu'une preuve coincide exactement avec l'execution du programme.
le programme est un type. quand on voit ça, on se dit qu'on en est
plus du tout loin, de ce concept.

bon, je suis bluffé la.




ça c'est une vision locale. mais globalement c'est rentable, même si
localement, ça peut couter plus cher.


Tu pourrais démontrer cette assertion par un calcul de complexité, même
qualitatif?



démontrer, c'est peut être beaucoup. ça tiendrait dans une these.
et c'est ce qu'expliquait mon prof (Dominique COLNET, c'est le pere
de SmallEiffel). d'apres lui, le GC était bien fondé.

ma perception du truc, c'est que si on pose une fenetre de temps sur
l'activité d'une machine (pour peu qu'elle soit "représentative", c'est à
dire pas du genre de taille epsilon voisin d'une micro-instruction) ,
on va trouver du temps ou la machine ne branle rien, ou alors fait des
choses qui n'ont pas matiere à préjudicier l'urgence d'autres taches si
on leur pique un peu de temps (je sais pas si je suis trés clair, la).
on place le garbage dans ce moment la. donc on gagne du temps
(on occupe du temps inutilisé), et ça simplifie le code.

un autre élément, c'est que l'effet "garbage" est voisin de celui de la
fermeture de processus. au lieu de rechercher/designer/enumerer
explicitement dans une "globalité" tout ce qui appartient au process
(chaque objet alloué), on bazarde le segment mémoire et donc tous
les objets qu'il contient. je ne peux pas être plus précis, mais il y a
dans le garbage quelque chose de cet ordre la.

du coup, la similarité avec le mécanisme d'alloc de page du systeme
tombe presque sous le sens. l'effet blocage par le garbage, bof. c'est
comme l'effet blocage pour cause de "page stealer" actif. la localité
et l'abondance des resources font que ça va bien.

ce qui est rigolo, c'est que ce mécanisme de page stealer (la mémoire
virtuelle) qui existe depuis des plombes, personne ne s'en plaint.
pourtant il existe. c'est un processus qui vole plein de temps et se
declenche toujours dans les moments ou il ne faut pas ? non, bon...
et pour ce mécanisme de GC qui découle de la même idée et est
sensé avoir les même propriétés, tout le monde crie au loup.




le concept de GC n'implique pas d'arreter tous les threads. cette
implantation le fait. c'est un choix. tant pis.


Tu as déjà vu une implémentation de GC qui ferait autrement?



avec deux sections critiques, entrer dans la premiere ne va pas
bloquer ceux qui entrent dans la deuxieme. ça, on arrive à le faire.
alors pourquoi pas ? localité quoi.




J'ai beau me torturer l'esprit, je ne vois pas comment c'est
conceptuelement faisable vu que le GC va déplacer en mémoire
des objets susceptibles d'êtres manipulés en même temps par les
threads de l'application.



fait un effort, si si :o)





Je repose la question : as-tu déjà vu une implémentation de GC qui fasse
comme çà? Toutes celles que je connais se déclenchent quand elles
détectent que le système est en passe de manquer de mémoire, ou bien
à intervalle régulier.



tous les gens que je connais au boulot font de l'attente active et du timer
pour voir si une donnée est arrivée sur un port, ou pour mettre à jour une
interface graphique. pourtant, le concept de message, le concept d'evenement
les concepts systemes d'entree sortie (synchrone, asynchrone, tout ça), ça
existe. donc...

je ne la connais pas (à tors, certainement), l'implantation du GC en .NET,
et je reste dans l'empirique. avec les calculs de sauvage que j'ai lancé
jusqu'à maintenant, je n'ai encore pas vu d'effets detestables.





- l'idiome RAII (Ressource Acquisition Is Initialization) est
innapliquable<snip/>




- Si la ressource est critique et doit être libérée le plus rapidement
possible (un périphérique matériel par exemple), alors oui c'est utile.



ben tu appelles la bonne fct quand besoin.
c'est une resource, c'est beaucoup plus qu'un simple objet :o).

bon, le but du jeu, c'est d'avoir visibilité => existence.

tirer parti du cas visibilité <=> pour filer du taf au destructeur autre que
libérer ce qui peut l'être, je ne sais pas si c'est une bonne chose. les
comportements trés particuliers du destructeur (genre appel d'une fct
virtual qui perd sa dynamique en C++ par exemple) me laissent penser
que le destructeur n'est pas la pour faire autre chose.

plus je regarde, moins ça a de sens. ça serait laisser la possibilité de
flinguer qqchose d'utilisé. justement ce qu'on ne veux pas.


- Plus important, pour écrire du code "exception safe", la seule façon de
faire en C# <snip/>



bof. que des class, et ça se demerde avec le tas. le garbage est la pour ça.
donc, on est dans le cas idéal. try catch en haut, (à la limite dans le
main),
et les throw en bas.

Ben justement, si je veux définir un objet à comportement polymorphique
(ou contenant un objet polymorphiqe pour être plus réaliste) mais à durée


de
vie automatique, je fais comment?



polymorphique ou pas, tu oublies auto.
comme dans un langage fonctionel, tu oublies l'affectation.
la duree de vie n'est plus ton probleme. seul la portée compte.
et sur fin de visibilité, tu appelles explicitement la methode qui va bien.

Quel exemple de Christophe? Je n'ai pas la référence dont tu parles.



c'est le post ou il parlait d'un bug du compilateur.

il créeait un struct Data au lieu d'une class Data pour gagner du temps à
l'execution. le struct était assimilé à une variable auto, donc détruit de
suite sortie de visibilité dans sa boucle, sans encombrer la mémoire à
domphe au bout de la 5000° iteration, sans prendre un temps conséquent
puisque le tas est plus lent que la pile, bref que des bonnes raisons
sémantiques :o)

et que faisait il dans sa boucle l'ami christophe ? il ajoutait l'élément
dans une collection avec un Add. donc en plus de la variable auto, on avait
l'élément copié dans le tas. lui, il pensait que les Data de sa collection
étaient quand même dans la pile. drole de notion du paranthesage. drole de
notion de l'économie.

> (je pense que c'est
> ça que tu appelles boxing unboxing).
Pour faire simple, le boxing/unboxing, c'est la capacité de C# de
transformer une "value type" en object :
int i 3;
object o =i; //ici, une copie de i est réalisée sur le tas.



ben voila, tout pile (ouarf ouarf ouarf, cte jeu de mots)

> je pense même qu'un jour,
> le compilateur sera doté d'un mécanisme de decision qui choisira
> localement entre struct ou class à la compilation.
Fichtre..., on parle bien du C# là? Parce qu'alors il faudra revoir les
définitions de class et struct dans ce langage vu que ces deux concepts ne
permettent pas de faire la même chose! Entre autres différences :
- une struct ne peut que hériter d'object et implémenter des interfaces



quand je disais struct ou class, c'était au sens du rangement de l'instance
(dans la pile, ou dans le tas)
struct ou class on des sémantiques différentes. c'est louable, même si
certains aspects son penibles.

la plupart veulent se servir de struct ou de class comme de auto ou de ptr.
ce qui est trés différent puisque struct/class concerne le type, et que
auto/ptr concerne l'instance.

pour ma part, on ne devrait avoir que des class, et c'est au compilo de
décider de l'emplacement de l'objet.
c'est un détail qui ne nous regarde plus, et qui n'a plus grand interet. cas
de christophe à l'appui.

Au passage, dans du code C++ *bien écrit*, il n'y a pas (ou très
peu) de delete.


c'est clair. une application qui fait de l'allocation à robinet
ouvert et passe un temps conséquent la dessus necessite qu'on
s'interroge.


Non, tu ne m'as pas compris (au passage, un programme .NET va
avoir tendance à faire beaucoup plus d'allocations mémoire qu'un
programme C++). : Je parle du fait qu'en C++ on s'arrange pour
que le langage fasse lui même le ménage (via les destructeurs) pour
les ressoures qu'on alloue et ce de manière synchrone.



tu veux dire le developpeur fasse lui même le ménage. maintenant,
l'allocation est synchrone, la restitution est asynchrone, et voila.
pile ou tas, c'est du foutage. c'est une optimisation du compilo, au
même titre que les variables register etc etc etc.


il ne s'agit pas de cela du tout. je t'invite à relire.


Je relis donc :
pour faire une comparaison, écrire les delete, c'est comme écrire du
code toutes les 3 lignes pour provoquer soit même le swap vers un
autre processus. ça fait perdre du temps à l'execution, ça prend une
place monstrueuse, ça donne au code une charge supplémentaire, et
conceptuellement, l'idée est naze.



Pourrais-tu m'expliquer ton parallélisme, parce que j'avoue que je ne vois
toujours pas le rapport entre le swap d'un thread à l'autre (qui sert à
faire plusieurs tâches en "pseudo-parallèle" sur un processeur) et la
politique de libération des ressources d'un programme donné.



tu me suis maintenant ? evidement, il n'y a pas un delete tous les 3 lignes,
mais dans certains cas. j'ai eu beaucoup de cas ou décider de la liberation
d'un objet était complexe.

il s'agit
d'opportunité du moment, et de complexité. je t'accorde
que ce n'est pas evident à saisir.





dans une analyse syntaxique, écrite avec des gentilles fonctions recursives.
je decide du type de l'objet et j'en fait un new TypeDecidé, et au fur et à
mesure que je remonte dans mes appels, le type de l'objet s'abstrait.
au fur et à mesure des cas, je repasse l'objet à une fonction, ou j'insere
l'objet dans une structure.parfois il en disparait suite à certaines
optimisations en locales. mais certaines fois, l'objet est à plusieurs
endroit dans la pile, et je ne sais pas si je peux le virer ou pas.
la, le GC est mon pote. les erreurs syntaxiques, je les geres par
exceptions.
la encore, le GC est mon pote.

évidement, encore faut il qu'il fonctionne. si on arrive à pénurie de
resources,
c'est qu'il y'a un probleme du côté du GC.

et des "structures de données" compliquées comme ça, j'en ai à la pelle.
évidement, si on écrit une structure de List, cela ne consomme pas
enormement de neurones d'écrire le destructeur. mais bon dans l'absolu :
ça sera toujours ça de moins d'écrit, donc toujours ça de moins qui
risque d'être faux. ça évite les fuites, truc fréquent donc je vote pour...



Non, c'est le moins qu'on puiss dire, essaie de clarifier!



c'est plus clair ?




bon pourquoi pa... Moi ce qui m'intéresse (et surtout mon patron!), c'est
*aujourd'hui* de savoir l'impact du choix de C# pour faire telle ou telle
chose, pas dans un futur hypothétique.



bof. hypotetique je te l'accorde. mais bon... ton code va vivre sa vie.
il sera réutilisé. faut voir tout ça. et faut minimiser l'effort dans la
durée.
choix local, choix global, chacun son truc.

Arnaud, je ne sais pas ce qu'il y a mais sur le coup la, et sur tes
posts precedents, je trouve que tu as bouffé du troll...


Fichtre, d'autres ont eu la même impression là??? Va peut être falloir que
je me soigne alors! ;-)



meuh non, c'est pas une maladie :o)

Sérieusement, ca ne serait pas toi qui ferait dans la paranoia trollesque
et manquerait un peu d'objectivité dans tes jugements?



ben d'objectivité certainement. j'ai adopté une attitude positive certes,
maintenant, des soucis, c'est comme tout le monde je pense, on a tous.
le Update du Dataset qui fait des trucs bizarres, tout ça...

paranoia trollesque, bof.
j'ai pas l'impression de la jouer Vincent Burel la.

.NET a d'immenses
qualités (la richesse et la qualité de la BC et du framework, la
simplicité de codage, la gestion des assembly et la fin du DLL-hell, ...),
mais tout MVP que je suis, ca ne m'empêche pas de rester critique
malgré tout!



de mon côté, je n'ai pas grande critique à formuler.
evidement, je ne connais de .Net que le sous ensemble qui m'interesse, et il
convient bien pour l'usage que j'en fait.

voila voila...
1 2