Bonsoir,
Je ne vous ferai pas perdre plus votre temps.
En effet, l'exception est maintenant déclanchée par le constructeur
et non plus par le destructeur alors que je n'ai pas changé le code
(moi rien comprendre). Le pb problème doit donc être plus général.
Va falloir revoir l'"architecture" du programme. (au fait, étudiant et
pas programmeur... Mais deux ans sans codé et on oublie vite la
théorie et les bases: analyser avant programmer)
Pour ceux que ça interesse.. (j'aimerai bien comprendre comme même en
fait ;-))
[..]
CrazyMarket.exe!std::basic_string<char,std::char_traits<char>,std::allocator
assign(const
std::basic_string<char,std::char_traits<char>,std::allocator<char> > &
_Right={...}, unsigned int _Roff=0, unsigned int _CountB94967295)
Line 599 + 0x10 C++
Bonsoir,
Je ne vous ferai pas perdre plus votre temps.
En effet, l'exception est maintenant déclanchée par le constructeur
et non plus par le destructeur alors que je n'ai pas changé le code
(moi rien comprendre). Le pb problème doit donc être plus général.
Va falloir revoir l'"architecture" du programme. (au fait, étudiant et
pas programmeur... Mais deux ans sans codé et on oublie vite la
théorie et les bases: analyser avant programmer)
Pour ceux que ça interesse.. (j'aimerai bien comprendre comme même en
fait ;-))
[..]
CrazyMarket.exe!std::basic_string<char,std::char_traits<char>,std::allocator
assign(const
std::basic_string<char,std::char_traits<char>,std::allocator<char> > &
_Right={...}, unsigned int _Roff=0, unsigned int _CountB94967295)
Line 599 + 0x10 C++
Bonsoir,
Je ne vous ferai pas perdre plus votre temps.
En effet, l'exception est maintenant déclanchée par le constructeur
et non plus par le destructeur alors que je n'ai pas changé le code
(moi rien comprendre). Le pb problème doit donc être plus général.
Va falloir revoir l'"architecture" du programme. (au fait, étudiant et
pas programmeur... Mais deux ans sans codé et on oublie vite la
théorie et les bases: analyser avant programmer)
Pour ceux que ça interesse.. (j'aimerai bien comprendre comme même en
fait ;-))
[..]
CrazyMarket.exe!std::basic_string<char,std::char_traits<char>,std::allocator
assign(const
std::basic_string<char,std::char_traits<char>,std::allocator<char> > &
_Right={...}, unsigned int _Roff=0, unsigned int _CountB94967295)
Line 599 + 0x10 C++
Patrick 'Zener' Brunet wrote:Patrick 'Zener' Brunet wrote:Je réponds à
[...]Sinon, il faut certainement des classes faites sur mésure
dans l'exception, pour gerer des chaînes sans allocation
dynamique.
Il m'est arrivé de développer de telles classes : elles sont
construites comme des objets globaux, sans allocation de
mémoire dynamique, et donc elles ne sont plus jamais
construites ni détruites : seulement réquisitionnées puis
restituées (elles fournissent une méthode static Throw() ).
Je ne comprends pas trop cette association pas d'allocation
dynamique -- objet global. J'ai bien des objets globaux qui font
de l'allocation dynamique. (J'ai même parfois des std::string
globaux.)
Pour ce qui est de la chaîne message, en fait j'avais défini
un protocole permettant de stocker dans le corps de
l'exception les éléments variants (2 entiers et un tableau de
127 + 1 caractères), la classe Exception offrant une fonction
type sprintf() contrôlée pour utiliser ça.
Tu n'as pas besoin d'un protocol, parce que tu pourrais réserver
aussi un tableau de caractères dans n'importe quelle classe
dérivée. (Tableau de type, s'entend, pourqu'il n'y a pas
d'allocation dynamique.) Certaines implémentations des
std::exception le font, je crois ; si tu passes un chaîne plus
long que le tableau fixe, elles essaient d'obtenir de la mémoire
dynamique (avec new (nothrow)), et si ça échoue, elles tronquent
la chaîne.
Mais ça n'évite pas totallement le besoin des allocations
dynamique. Le problème, c'est qu'il faut que le système stocke
l'exception même quelque part. Et que ça ne peut pas être sur la
pile, parce qu'elle fait detruire la pile. Et que ça ne peut pas
être en mémoire statique, parce qu'il peut y avoir d'autres
exceptions lors du stack unwinding. (A propos : comment est-ce
qu'on dit « stack unwinding » en français ?) Alors,
l'implémentation est obligée à allouer la mémoire pour
l'exception dynamiquement. (En général, l'implémentation utilise
un tas ou une pile à part pour ça. Et certainement pas operator
new. Mais c'est dynamique quand même.)
Ca permet donc de justifier ma réponse à la suite...
Sinon pour ce qui est de l'abort(), étant plutôt orienté
informatique-industrielle-sans-renoncement-à-la-mémoire-dynamique,
évidemment c'est hors de question (et donc il faudra que je me
remette un peu au courant des évolutions de la gestion
"optimiste" de mémoire sous Linux depuis 2 ans).
Je suis sceptique en ce qui concerne les possibilités d'un
logiciel critique avec utilisation de la mémoire dynamique.
Mais il y a bien des programmes industriels qui ne sont pas
critiques, et qui peuvent supporter un abort, pourvu que la
probabilité ou la fréquence en soit assez faible. (À vrai dire,
tout système critique doit être secouru, aussi. De façon à ce
qu'un crash ne soit pas fatal pour le système entier.) De toute
façon, si tu te bases sur un système d'exploitation courante,
Windows, ou un Unix, il faut l'accepter, parce qu'ils abortent
tous le processus si l'épuisement de la mémoire se produit lors
de l'agrandissement de la pile.
Aussi, on accepte souvent à prendre la « risque », en s'assurant
qu'il n'y a que l'application en question qui tourne sur la
machine, et que la machine a assez de mémoire pour ne pas en
épuiser.
2) Votre exception est transmise par copie semble-t-il, et
non par adresse.
Toute exception est transmise par copie. Il le faut bien,
puisqu'on va déballer la pile, et la mémoire où
l'utilisateur le construit (comme temporaire) va
disparaître.
Avec ma convention précédente, justement, c'était un pointeur
vers l'exception qui était transmis, lui donc par copie en
effet.
D'accord. Tu as donc un objet statique, et tu lèves une
exception du type pointeur à l'objet. Seulement, qu'est-ce qui
se passe si les exceptions s'imbriquent, et que tu veux lever
une deuxième exception du même type, alors que la première est
toujours active ? Ou est-ce que tu as conçu l'application pour
que le cas ne peut pas se produire ?
Cela implique tout un tas de cycles de
création/copie/destruction de chaînes, ce qui est d'une
part très inefficace, et d'autre part remultiplie les cas
d'échec.
Ça implique *une* copie, c'est tout. Qu'il l'attrappe par
copie implique une deuxième. Rien devant le coût d'une
exception en général.
Et s'il utilise throw; dans un bloc catch() pour la relancer ?
Pas de copie, je crois. Je ne suis pas sûr, mais je crois que le
throw sans paramètres est garantie de réutiliser l'objet
existant.Je me souviens-là des tests que j'ai pu faire lors de la mise
au point d'une classe genre "string", au niveau de l'opérateur
d'affectation et du constructeur de copie (et en prenant en
compte l'instance anonyme transitoire lorsqu'on retourne un
objet entier plutôt qu'un pointeur). Donc, selon comment cette
instance d'exception est construite, remplie puis "lancée",
j'hésite sur le nombre possible de copies.
Le nombre de copies n'est de toute façon pas bien spécifié.
Conceptuellement, tu construis l'objet « sur la pile » avec une
expression du genre X(), et ensuite, cet objet est copié
ailleurs. Mais un compilateur a le droit de faire en sort que
l'objet temporaire que tu construis, et la copie « ailleurs »,
sont en fait le même objet, et supprimer l'action de copier.
[...]Bienheureux les concepteurs qui ont réussi à recruter un
employeur sérieux !
En effet. J'ai vu le problème plus d'une fois. On a une équipe
de programmeurs. Qui coûte, avec les charges et al., environ
500 000 Euros. Et on réfuse l'achat d'un outil à 10 000 Euros
qui leur ferait gagner 20% de temps -- c-à-d 100 000 Euros par
an.
Mais d'après ce que je vois, la situation s'améliore, et que
l'utilisation de Purify est quasi-universelle chez mes clients
aujourd'hui.Moi je suis à nouveau en train de chercher, et j'espère que je
ne vais pas à nouveau devoir rafistoler les moutons crevés
laissés par le type d'avant, la conception des produits
d'avenir de la boîte étant dans le même temps confiée à des
bricolos pour raisons de budget :-@
Heureusement qu'on peut encore faire de la R&D sérieuse durant
ses loisirs :-D
Figure-toi qu'il y a, aujourd'hui, des boîtes qui savent estîmer
un travail bien fait, et qui sont prêt à donner aux développeurs
ce qu'il faut pour le faire. (Évidemment, elles n'embauchent pas
tous les jours. Mais en cherchant assez longtemps, on finit par
les dénicher.)
Patrick 'Zener' Brunet wrote:
Patrick 'Zener' Brunet wrote:
Je réponds à superbabar51@hotmail.com
[...]
Sinon, il faut certainement des classes faites sur mésure
dans l'exception, pour gerer des chaînes sans allocation
dynamique.
Il m'est arrivé de développer de telles classes : elles sont
construites comme des objets globaux, sans allocation de
mémoire dynamique, et donc elles ne sont plus jamais
construites ni détruites : seulement réquisitionnées puis
restituées (elles fournissent une méthode static Throw() ).
Je ne comprends pas trop cette association pas d'allocation
dynamique -- objet global. J'ai bien des objets globaux qui font
de l'allocation dynamique. (J'ai même parfois des std::string
globaux.)
Pour ce qui est de la chaîne message, en fait j'avais défini
un protocole permettant de stocker dans le corps de
l'exception les éléments variants (2 entiers et un tableau de
127 + 1 caractères), la classe Exception offrant une fonction
type sprintf() contrôlée pour utiliser ça.
Tu n'as pas besoin d'un protocol, parce que tu pourrais réserver
aussi un tableau de caractères dans n'importe quelle classe
dérivée. (Tableau de type, s'entend, pourqu'il n'y a pas
d'allocation dynamique.) Certaines implémentations des
std::exception le font, je crois ; si tu passes un chaîne plus
long que le tableau fixe, elles essaient d'obtenir de la mémoire
dynamique (avec new (nothrow)), et si ça échoue, elles tronquent
la chaîne.
Mais ça n'évite pas totallement le besoin des allocations
dynamique. Le problème, c'est qu'il faut que le système stocke
l'exception même quelque part. Et que ça ne peut pas être sur la
pile, parce qu'elle fait detruire la pile. Et que ça ne peut pas
être en mémoire statique, parce qu'il peut y avoir d'autres
exceptions lors du stack unwinding. (A propos : comment est-ce
qu'on dit « stack unwinding » en français ?) Alors,
l'implémentation est obligée à allouer la mémoire pour
l'exception dynamiquement. (En général, l'implémentation utilise
un tas ou une pile à part pour ça. Et certainement pas operator
new. Mais c'est dynamique quand même.)
Ca permet donc de justifier ma réponse à la suite...
Sinon pour ce qui est de l'abort(), étant plutôt orienté
informatique-industrielle-sans-renoncement-à-la-mémoire-dynamique,
évidemment c'est hors de question (et donc il faudra que je me
remette un peu au courant des évolutions de la gestion
"optimiste" de mémoire sous Linux depuis 2 ans).
Je suis sceptique en ce qui concerne les possibilités d'un
logiciel critique avec utilisation de la mémoire dynamique.
Mais il y a bien des programmes industriels qui ne sont pas
critiques, et qui peuvent supporter un abort, pourvu que la
probabilité ou la fréquence en soit assez faible. (À vrai dire,
tout système critique doit être secouru, aussi. De façon à ce
qu'un crash ne soit pas fatal pour le système entier.) De toute
façon, si tu te bases sur un système d'exploitation courante,
Windows, ou un Unix, il faut l'accepter, parce qu'ils abortent
tous le processus si l'épuisement de la mémoire se produit lors
de l'agrandissement de la pile.
Aussi, on accepte souvent à prendre la « risque », en s'assurant
qu'il n'y a que l'application en question qui tourne sur la
machine, et que la machine a assez de mémoire pour ne pas en
épuiser.
2) Votre exception est transmise par copie semble-t-il, et
non par adresse.
Toute exception est transmise par copie. Il le faut bien,
puisqu'on va déballer la pile, et la mémoire où
l'utilisateur le construit (comme temporaire) va
disparaître.
Avec ma convention précédente, justement, c'était un pointeur
vers l'exception qui était transmis, lui donc par copie en
effet.
D'accord. Tu as donc un objet statique, et tu lèves une
exception du type pointeur à l'objet. Seulement, qu'est-ce qui
se passe si les exceptions s'imbriquent, et que tu veux lever
une deuxième exception du même type, alors que la première est
toujours active ? Ou est-ce que tu as conçu l'application pour
que le cas ne peut pas se produire ?
Cela implique tout un tas de cycles de
création/copie/destruction de chaînes, ce qui est d'une
part très inefficace, et d'autre part remultiplie les cas
d'échec.
Ça implique *une* copie, c'est tout. Qu'il l'attrappe par
copie implique une deuxième. Rien devant le coût d'une
exception en général.
Et s'il utilise throw; dans un bloc catch() pour la relancer ?
Pas de copie, je crois. Je ne suis pas sûr, mais je crois que le
throw sans paramètres est garantie de réutiliser l'objet
existant.
Je me souviens-là des tests que j'ai pu faire lors de la mise
au point d'une classe genre "string", au niveau de l'opérateur
d'affectation et du constructeur de copie (et en prenant en
compte l'instance anonyme transitoire lorsqu'on retourne un
objet entier plutôt qu'un pointeur). Donc, selon comment cette
instance d'exception est construite, remplie puis "lancée",
j'hésite sur le nombre possible de copies.
Le nombre de copies n'est de toute façon pas bien spécifié.
Conceptuellement, tu construis l'objet « sur la pile » avec une
expression du genre X(), et ensuite, cet objet est copié
ailleurs. Mais un compilateur a le droit de faire en sort que
l'objet temporaire que tu construis, et la copie « ailleurs »,
sont en fait le même objet, et supprimer l'action de copier.
[...]
Bienheureux les concepteurs qui ont réussi à recruter un
employeur sérieux !
En effet. J'ai vu le problème plus d'une fois. On a une équipe
de programmeurs. Qui coûte, avec les charges et al., environ
500 000 Euros. Et on réfuse l'achat d'un outil à 10 000 Euros
qui leur ferait gagner 20% de temps -- c-à-d 100 000 Euros par
an.
Mais d'après ce que je vois, la situation s'améliore, et que
l'utilisation de Purify est quasi-universelle chez mes clients
aujourd'hui.
Moi je suis à nouveau en train de chercher, et j'espère que je
ne vais pas à nouveau devoir rafistoler les moutons crevés
laissés par le type d'avant, la conception des produits
d'avenir de la boîte étant dans le même temps confiée à des
bricolos pour raisons de budget :-@
Heureusement qu'on peut encore faire de la R&D sérieuse durant
ses loisirs :-D
Figure-toi qu'il y a, aujourd'hui, des boîtes qui savent estîmer
un travail bien fait, et qui sont prêt à donner aux développeurs
ce qu'il faut pour le faire. (Évidemment, elles n'embauchent pas
tous les jours. Mais en cherchant assez longtemps, on finit par
les dénicher.)
Patrick 'Zener' Brunet wrote:Patrick 'Zener' Brunet wrote:Je réponds à
[...]Sinon, il faut certainement des classes faites sur mésure
dans l'exception, pour gerer des chaînes sans allocation
dynamique.
Il m'est arrivé de développer de telles classes : elles sont
construites comme des objets globaux, sans allocation de
mémoire dynamique, et donc elles ne sont plus jamais
construites ni détruites : seulement réquisitionnées puis
restituées (elles fournissent une méthode static Throw() ).
Je ne comprends pas trop cette association pas d'allocation
dynamique -- objet global. J'ai bien des objets globaux qui font
de l'allocation dynamique. (J'ai même parfois des std::string
globaux.)
Pour ce qui est de la chaîne message, en fait j'avais défini
un protocole permettant de stocker dans le corps de
l'exception les éléments variants (2 entiers et un tableau de
127 + 1 caractères), la classe Exception offrant une fonction
type sprintf() contrôlée pour utiliser ça.
Tu n'as pas besoin d'un protocol, parce que tu pourrais réserver
aussi un tableau de caractères dans n'importe quelle classe
dérivée. (Tableau de type, s'entend, pourqu'il n'y a pas
d'allocation dynamique.) Certaines implémentations des
std::exception le font, je crois ; si tu passes un chaîne plus
long que le tableau fixe, elles essaient d'obtenir de la mémoire
dynamique (avec new (nothrow)), et si ça échoue, elles tronquent
la chaîne.
Mais ça n'évite pas totallement le besoin des allocations
dynamique. Le problème, c'est qu'il faut que le système stocke
l'exception même quelque part. Et que ça ne peut pas être sur la
pile, parce qu'elle fait detruire la pile. Et que ça ne peut pas
être en mémoire statique, parce qu'il peut y avoir d'autres
exceptions lors du stack unwinding. (A propos : comment est-ce
qu'on dit « stack unwinding » en français ?) Alors,
l'implémentation est obligée à allouer la mémoire pour
l'exception dynamiquement. (En général, l'implémentation utilise
un tas ou une pile à part pour ça. Et certainement pas operator
new. Mais c'est dynamique quand même.)
Ca permet donc de justifier ma réponse à la suite...
Sinon pour ce qui est de l'abort(), étant plutôt orienté
informatique-industrielle-sans-renoncement-à-la-mémoire-dynamique,
évidemment c'est hors de question (et donc il faudra que je me
remette un peu au courant des évolutions de la gestion
"optimiste" de mémoire sous Linux depuis 2 ans).
Je suis sceptique en ce qui concerne les possibilités d'un
logiciel critique avec utilisation de la mémoire dynamique.
Mais il y a bien des programmes industriels qui ne sont pas
critiques, et qui peuvent supporter un abort, pourvu que la
probabilité ou la fréquence en soit assez faible. (À vrai dire,
tout système critique doit être secouru, aussi. De façon à ce
qu'un crash ne soit pas fatal pour le système entier.) De toute
façon, si tu te bases sur un système d'exploitation courante,
Windows, ou un Unix, il faut l'accepter, parce qu'ils abortent
tous le processus si l'épuisement de la mémoire se produit lors
de l'agrandissement de la pile.
Aussi, on accepte souvent à prendre la « risque », en s'assurant
qu'il n'y a que l'application en question qui tourne sur la
machine, et que la machine a assez de mémoire pour ne pas en
épuiser.
2) Votre exception est transmise par copie semble-t-il, et
non par adresse.
Toute exception est transmise par copie. Il le faut bien,
puisqu'on va déballer la pile, et la mémoire où
l'utilisateur le construit (comme temporaire) va
disparaître.
Avec ma convention précédente, justement, c'était un pointeur
vers l'exception qui était transmis, lui donc par copie en
effet.
D'accord. Tu as donc un objet statique, et tu lèves une
exception du type pointeur à l'objet. Seulement, qu'est-ce qui
se passe si les exceptions s'imbriquent, et que tu veux lever
une deuxième exception du même type, alors que la première est
toujours active ? Ou est-ce que tu as conçu l'application pour
que le cas ne peut pas se produire ?
Cela implique tout un tas de cycles de
création/copie/destruction de chaînes, ce qui est d'une
part très inefficace, et d'autre part remultiplie les cas
d'échec.
Ça implique *une* copie, c'est tout. Qu'il l'attrappe par
copie implique une deuxième. Rien devant le coût d'une
exception en général.
Et s'il utilise throw; dans un bloc catch() pour la relancer ?
Pas de copie, je crois. Je ne suis pas sûr, mais je crois que le
throw sans paramètres est garantie de réutiliser l'objet
existant.Je me souviens-là des tests que j'ai pu faire lors de la mise
au point d'une classe genre "string", au niveau de l'opérateur
d'affectation et du constructeur de copie (et en prenant en
compte l'instance anonyme transitoire lorsqu'on retourne un
objet entier plutôt qu'un pointeur). Donc, selon comment cette
instance d'exception est construite, remplie puis "lancée",
j'hésite sur le nombre possible de copies.
Le nombre de copies n'est de toute façon pas bien spécifié.
Conceptuellement, tu construis l'objet « sur la pile » avec une
expression du genre X(), et ensuite, cet objet est copié
ailleurs. Mais un compilateur a le droit de faire en sort que
l'objet temporaire que tu construis, et la copie « ailleurs »,
sont en fait le même objet, et supprimer l'action de copier.
[...]Bienheureux les concepteurs qui ont réussi à recruter un
employeur sérieux !
En effet. J'ai vu le problème plus d'une fois. On a une équipe
de programmeurs. Qui coûte, avec les charges et al., environ
500 000 Euros. Et on réfuse l'achat d'un outil à 10 000 Euros
qui leur ferait gagner 20% de temps -- c-à-d 100 000 Euros par
an.
Mais d'après ce que je vois, la situation s'améliore, et que
l'utilisation de Purify est quasi-universelle chez mes clients
aujourd'hui.Moi je suis à nouveau en train de chercher, et j'espère que je
ne vais pas à nouveau devoir rafistoler les moutons crevés
laissés par le type d'avant, la conception des produits
d'avenir de la boîte étant dans le même temps confiée à des
bricolos pour raisons de budget :-@
Heureusement qu'on peut encore faire de la R&D sérieuse durant
ses loisirs :-D
Figure-toi qu'il y a, aujourd'hui, des boîtes qui savent estîmer
un travail bien fait, et qui sont prêt à donner aux développeurs
ce qu'il faut pour le faire. (Évidemment, elles n'embauchent pas
tous les jours. Mais en cherchant assez longtemps, on finit par
les dénicher.)
Patrick 'Zener' Brunet wrote:Je réponds à qui a
écrit : > Patrick 'Zener' Brunet wrote:Je réponds à
[...]Sinon, il faut certainement des classes faites sur mésure
dans l'exception, pour gerer des chaînes sans allocation
dynamique.
Il m'est arrivé de développer de telles classes : elles
sont construites comme des objets globaux, sans allocation
de mémoire dynamique, et donc elles ne sont plus jamais
construites ni détruites : seulement réquisitionnées puis
restituées (elles fournissent une méthode static Throw() ).
Je ne comprends pas trop cette association pas d'allocation
dynamique -- objet global. J'ai bien des objets globaux qui
font de l'allocation dynamique. (J'ai même parfois des
std::string globaux.)
Je veux dire objets globaux **et** ne faisant pas d'allocation
dynamique, afin de n'avoir aucune possiblité d'échec à la
construction.Pour ce qui est de la chaîne message, en fait j'avais
défini un protocole permettant de stocker dans le corps de
l'exception les éléments variants (2 entiers et un tableau
de 127 + 1 caractères), la classe Exception offrant une
fonction type sprintf() contrôlée pour utiliser ça.
Tu n'as pas besoin d'un protocol, parce que tu pourrais
réserver aussi un tableau de caractères dans n'importe
quelle classe dérivée. (Tableau de type, s'entend, pourqu'il
n'y a pas d'allocation dynamique.) Certaines implémentations
des std::exception le font, je crois ; si tu passes un
chaîne plus long que le tableau fixe, elles essaient
d'obtenir de la mémoire dynamique (avec new (nothrow)), et
si ça échoue, elles tronquent la chaîne.
J'ai pris en compte aussi le critère de vitesse,
et par ailleurs j'ai voulu totalement découpler ça de
l'allocation dynamique parce que mes classes travaillent avec
toute une variété de heaps (positionnement et algorithme
d'allocation).
Donc j'ai mis les exception à part. Partant du principe qu'on
n'a pas besoin d'une chaîne volumineuse pour cet usage, j'ai
utilisé une classe à moi qui permet de faire du CString sur un
tableau statique, avec une taille figée (constante de
précompilation). Le pool d'exceptions préallouées ne
représente plus rien dans le contexte d'un logiciel "moderne".
Mais ça n'évite pas totallement le besoin des allocations
dynamique. Le problème, c'est qu'il faut que le système
stocke l'exception même quelque part. Et que ça ne peut pas
être sur la pile, parce qu'elle fait detruire la pile. Et
que ça ne peut pas être en mémoire statique, parce qu'il
peut y avoir d'autres exceptions lors du stack unwinding. (A
propos : comment est-ce qu'on dit « stack unwinding » en
français ?) Alors, l'implémentation est obligée à allouer la
mémoire pour l'exception dynamiquement. (En général,
l'implémentation utilise un tas ou une pile à part pour
ça. Et certainement pas operator new. Mais c'est dynamique
quand même.)
J'ai prévu un pool d'exceptions recyclables, et donc la
fonction Throw en réquisitionne une qui ne le soit pas
déjà. Cela pose évidemment la question de la taille de ce
pool. J'ai opté pour un dimensionnement par constante de
précompilation bien sûr, et comme mes classes sont conçue pour
minimiser les cascades d'échecs (elles font de la récupération
une priorité et donc évitent d'agraver la situation), j'ai
décidé qu'au-delà de 5 exceptions en cours, on dépassait
largement les bornes du raisonnable.
Ca permet donc de justifier ma réponse à la suite...
Sinon pour ce qui est de l'abort(), étant plutôt orienté
informatique-industrielle-sans-renoncement-à-la-mémoire-dynamique,
évidemment c'est hors de question (et donc il faudra que je
me remette un peu au courant des évolutions de la gestion
"optimiste" de mémoire sous Linux depuis 2 ans).
Je suis sceptique en ce qui concerne les possibilités d'un
logiciel critique avec utilisation de la mémoire dynamique.
Critique temps-réel, je pense aussi. Mais sans aller jusque
là, compte tenu du coût et de l'aspect spartiate des systèmes
résolument industriels, il n'est pas rare de confier à un PC
la supervision d'un process avec des contraintes temps-réel
assez fortes.
Nous l'avons fait dans des installations de supervision de tri
ou de préparation de commande par exemple (avec des taux de
l'ordre de 6 transactions par secondes, chacune impliquant un
moulinage de structures en mémoire, des transferts série vers
un automate, réseau vers un AS400, et une ou deux transactions
en base de données genre Sybase ou Oracle. Ca marche très bien
sur un PC correctement dimensionné, mais bien sûr il est hors
de question de jouer ou de surfer sur le net en même temps !
Mais il y a bien des programmes industriels qui ne sont pas
critiques, et qui peuvent supporter un abort, pourvu que la
probabilité ou la fréquence en soit assez faible. (À vrai
dire, tout système critique doit être secouru, aussi. De
façon à ce qu'un crash ne soit pas fatal pour le système
entier.) De toute façon, si tu te bases sur un système
d'exploitation courante, Windows, ou un Unix, il faut
l'accepter, parce qu'ils abortent tous le processus si
l'épuisement de la mémoire se produit lors de
l'agrandissement de la pile.
Pas trop d'accord : s'il y a une exception prévue dans
operator new, ça suppose qu'on devrait avoir une chance d'en
tirer parti, et je me suis donné beaucoup de mal pour ça.
Je sais écrire des applications qui sont conscientes de leurs
ressources et qui savent se récupérer sur des situations
dégradées. Alors bien sûr quand j'ai appris que sous Linux il
y avait un abort() dans le new_handler parce que le système
faisait le béni-oui-oui et tuait des process quand il se
trouvait au pied du mur, évidemment j'ai trouvé ça plutôt ...
NULL. J'espère que ça a évolué.
Il faut savoir aussi que certains process (et pas seulement
dans le domaine de l'I.A.) mettent en jeu des structures âvec
un tel entrelacement de pointeurs, qu'il est peu envisageable
(ou au moins très laborieux) de les reconstruire après un
crash). J'ai dû inventer une technologie pour offrir cette
immunité à un logiciel de la gamme ci-dessus, dans le contexte
d'une éventuelle panne de courant. Ca marche bien même à plein
régime. Mais évidemment si le système se met à faire du
sabordage aléatoire, on n'a plus qu'à chercher un portage
d'Oracle sur rack OS/9 !Aussi, on accepte souvent à prendre la « risque », en
s'assurant qu'il n'y a que l'application en question qui
tourne sur la machine, et que la machine a assez de mémoire
pour ne pas en épuiser.
Sur le genre de système évoqué, ça passe aussi par une bonne
gestion de l'émiettement, c'est ce qui me conduit à utiliser
des heaps spéciaux - et aussi des fichiers, l'expérience
martienne l'a montré :-D2) Votre exception est transmise par copie semble-t-il, et
non par adresse.
Toute exception est transmise par copie. Il le faut bien,
puisqu'on va déballer la pile, et la mémoire où
l'utilisateur le construit (comme temporaire) va
disparaître.
Avec ma convention précédente, justement, c'était un
pointeur vers l'exception qui était transmis, lui donc par
copie en effet.
D'accord. Tu as donc un objet statique, et tu lèves une
exception du type pointeur à l'objet. Seulement, qu'est-ce
qui se passe si les exceptions s'imbriquent, et que tu veux
lever une deuxième exception du même type, alors que la
première est toujours active ? Ou est-ce que tu as conçu
l'application pour que le cas ne peut pas se produire ?
Il y a donc un pool d'exceptions de taille "raisonnable".
Cela implique tout un tas de cycles de
création/copie/destruction de chaînes, ce qui est d'une
part très inefficace, et d'autre part remultiplie les cas
d'échec.
Ça implique *une* copie, c'est tout. Qu'il l'attrappe par
copie implique une deuxième. Rien devant le coût d'une
exception en général.
Et s'il utilise throw; dans un bloc catch() pour la
relancer ?
Pas de copie, je crois. Je ne suis pas sûr, mais je crois
que le throw sans paramètres est garantie de réutiliser
l'objet existant.Je me souviens-là des tests que j'ai pu faire lors de la
mise au point d'une classe genre "string", au niveau de
l'opérateur d'affectation et du constructeur de copie (et
en prenant en compte l'instance anonyme transitoire
lorsqu'on retourne un objet entier plutôt qu'un pointeur).
Donc, selon comment cette instance d'exception est
construite, remplie puis "lancée", j'hésite sur le nombre
possible de copies.
Le nombre de copies n'est de toute façon pas bien spécifié.
Conceptuellement, tu construis l'objet « sur la pile » avec
une expression du genre X(), et ensuite, cet objet est copié
ailleurs. Mais un compilateur a le droit de faire en sort
que l'objet temporaire que tu construis, et la copie «
ailleurs », sont en fait le même objet, et supprimer
l'action de copier.
La pire séquece que j'ai pu tracer au debugger était la suivante :
CString ab;
...
ab = CString( "aaaaa") + "bbbbb";
Tout le monde fait ça pour avoir la facilité de l'opérateur de
concaténation, mais bonjour la chaîne d'allocations, copies et
destructions avec libération de mémoire ! Notamment avec le
compilo du VC++6.0, on voit bien la CString anonyme retournée
par operator + C'a m'a tellement révolté que j'ai conçu un
mécanisme permettant à une chaîne de "donner son buffer" et de
se laisser détruire vide, plutôt que de demander à l'autre
d'en prendre copie. Dans l'idiome a = b + c; le gain est
énorme.
Heureusement qu'on peut encore faire de la R&D sérieuse
durant ses loisirs :-D
Figure-toi qu'il y a, aujourd'hui, des boîtes qui savent
estîmer un travail bien fait, et qui sont prêt à donner aux
développeurs ce qu'il faut pour le faire. (Évidemment, elles
n'embauchent pas tous les jours. Mais en cherchant assez
longtemps, on finit par les dénicher.)
Oui, ça devient un métier en soi, surtout quand on n'est pas
assez intégré au réseau pour être connu. C'est pour ça que
j'ai commencé à créer une présence sur le web avec un ami
plutôt commercial, mais ça met du temps à démarrer...
L'innovation fait peut plus qu'elle ne passionne. Et donc
finalement on a davantage envie de monter sa boîte que de
retrouver un employeur.
Patrick 'Zener' Brunet wrote:
Je réponds à kanze@gabi-soft.fr <kanze@gabi-soft.fr> qui a
écrit : > Patrick 'Zener' Brunet wrote:
Je réponds à superbabar51@hotmail.com
[...]
Sinon, il faut certainement des classes faites sur mésure
dans l'exception, pour gerer des chaînes sans allocation
dynamique.
Il m'est arrivé de développer de telles classes : elles
sont construites comme des objets globaux, sans allocation
de mémoire dynamique, et donc elles ne sont plus jamais
construites ni détruites : seulement réquisitionnées puis
restituées (elles fournissent une méthode static Throw() ).
Je ne comprends pas trop cette association pas d'allocation
dynamique -- objet global. J'ai bien des objets globaux qui
font de l'allocation dynamique. (J'ai même parfois des
std::string globaux.)
Je veux dire objets globaux **et** ne faisant pas d'allocation
dynamique, afin de n'avoir aucune possiblité d'échec à la
construction.
Pour ce qui est de la chaîne message, en fait j'avais
défini un protocole permettant de stocker dans le corps de
l'exception les éléments variants (2 entiers et un tableau
de 127 + 1 caractères), la classe Exception offrant une
fonction type sprintf() contrôlée pour utiliser ça.
Tu n'as pas besoin d'un protocol, parce que tu pourrais
réserver aussi un tableau de caractères dans n'importe
quelle classe dérivée. (Tableau de type, s'entend, pourqu'il
n'y a pas d'allocation dynamique.) Certaines implémentations
des std::exception le font, je crois ; si tu passes un
chaîne plus long que le tableau fixe, elles essaient
d'obtenir de la mémoire dynamique (avec new (nothrow)), et
si ça échoue, elles tronquent la chaîne.
J'ai pris en compte aussi le critère de vitesse,
et par ailleurs j'ai voulu totalement découpler ça de
l'allocation dynamique parce que mes classes travaillent avec
toute une variété de heaps (positionnement et algorithme
d'allocation).
Donc j'ai mis les exception à part. Partant du principe qu'on
n'a pas besoin d'une chaîne volumineuse pour cet usage, j'ai
utilisé une classe à moi qui permet de faire du CString sur un
tableau statique, avec une taille figée (constante de
précompilation). Le pool d'exceptions préallouées ne
représente plus rien dans le contexte d'un logiciel "moderne".
Mais ça n'évite pas totallement le besoin des allocations
dynamique. Le problème, c'est qu'il faut que le système
stocke l'exception même quelque part. Et que ça ne peut pas
être sur la pile, parce qu'elle fait detruire la pile. Et
que ça ne peut pas être en mémoire statique, parce qu'il
peut y avoir d'autres exceptions lors du stack unwinding. (A
propos : comment est-ce qu'on dit « stack unwinding » en
français ?) Alors, l'implémentation est obligée à allouer la
mémoire pour l'exception dynamiquement. (En général,
l'implémentation utilise un tas ou une pile à part pour
ça. Et certainement pas operator new. Mais c'est dynamique
quand même.)
J'ai prévu un pool d'exceptions recyclables, et donc la
fonction Throw en réquisitionne une qui ne le soit pas
déjà. Cela pose évidemment la question de la taille de ce
pool. J'ai opté pour un dimensionnement par constante de
précompilation bien sûr, et comme mes classes sont conçue pour
minimiser les cascades d'échecs (elles font de la récupération
une priorité et donc évitent d'agraver la situation), j'ai
décidé qu'au-delà de 5 exceptions en cours, on dépassait
largement les bornes du raisonnable.
Ca permet donc de justifier ma réponse à la suite...
Sinon pour ce qui est de l'abort(), étant plutôt orienté
informatique-industrielle-sans-renoncement-à-la-mémoire-dynamique,
évidemment c'est hors de question (et donc il faudra que je
me remette un peu au courant des évolutions de la gestion
"optimiste" de mémoire sous Linux depuis 2 ans).
Je suis sceptique en ce qui concerne les possibilités d'un
logiciel critique avec utilisation de la mémoire dynamique.
Critique temps-réel, je pense aussi. Mais sans aller jusque
là, compte tenu du coût et de l'aspect spartiate des systèmes
résolument industriels, il n'est pas rare de confier à un PC
la supervision d'un process avec des contraintes temps-réel
assez fortes.
Nous l'avons fait dans des installations de supervision de tri
ou de préparation de commande par exemple (avec des taux de
l'ordre de 6 transactions par secondes, chacune impliquant un
moulinage de structures en mémoire, des transferts série vers
un automate, réseau vers un AS400, et une ou deux transactions
en base de données genre Sybase ou Oracle. Ca marche très bien
sur un PC correctement dimensionné, mais bien sûr il est hors
de question de jouer ou de surfer sur le net en même temps !
Mais il y a bien des programmes industriels qui ne sont pas
critiques, et qui peuvent supporter un abort, pourvu que la
probabilité ou la fréquence en soit assez faible. (À vrai
dire, tout système critique doit être secouru, aussi. De
façon à ce qu'un crash ne soit pas fatal pour le système
entier.) De toute façon, si tu te bases sur un système
d'exploitation courante, Windows, ou un Unix, il faut
l'accepter, parce qu'ils abortent tous le processus si
l'épuisement de la mémoire se produit lors de
l'agrandissement de la pile.
Pas trop d'accord : s'il y a une exception prévue dans
operator new, ça suppose qu'on devrait avoir une chance d'en
tirer parti, et je me suis donné beaucoup de mal pour ça.
Je sais écrire des applications qui sont conscientes de leurs
ressources et qui savent se récupérer sur des situations
dégradées. Alors bien sûr quand j'ai appris que sous Linux il
y avait un abort() dans le new_handler parce que le système
faisait le béni-oui-oui et tuait des process quand il se
trouvait au pied du mur, évidemment j'ai trouvé ça plutôt ...
NULL. J'espère que ça a évolué.
Il faut savoir aussi que certains process (et pas seulement
dans le domaine de l'I.A.) mettent en jeu des structures âvec
un tel entrelacement de pointeurs, qu'il est peu envisageable
(ou au moins très laborieux) de les reconstruire après un
crash). J'ai dû inventer une technologie pour offrir cette
immunité à un logiciel de la gamme ci-dessus, dans le contexte
d'une éventuelle panne de courant. Ca marche bien même à plein
régime. Mais évidemment si le système se met à faire du
sabordage aléatoire, on n'a plus qu'à chercher un portage
d'Oracle sur rack OS/9 !
Aussi, on accepte souvent à prendre la « risque », en
s'assurant qu'il n'y a que l'application en question qui
tourne sur la machine, et que la machine a assez de mémoire
pour ne pas en épuiser.
Sur le genre de système évoqué, ça passe aussi par une bonne
gestion de l'émiettement, c'est ce qui me conduit à utiliser
des heaps spéciaux - et aussi des fichiers, l'expérience
martienne l'a montré :-D
2) Votre exception est transmise par copie semble-t-il, et
non par adresse.
Toute exception est transmise par copie. Il le faut bien,
puisqu'on va déballer la pile, et la mémoire où
l'utilisateur le construit (comme temporaire) va
disparaître.
Avec ma convention précédente, justement, c'était un
pointeur vers l'exception qui était transmis, lui donc par
copie en effet.
D'accord. Tu as donc un objet statique, et tu lèves une
exception du type pointeur à l'objet. Seulement, qu'est-ce
qui se passe si les exceptions s'imbriquent, et que tu veux
lever une deuxième exception du même type, alors que la
première est toujours active ? Ou est-ce que tu as conçu
l'application pour que le cas ne peut pas se produire ?
Il y a donc un pool d'exceptions de taille "raisonnable".
Cela implique tout un tas de cycles de
création/copie/destruction de chaînes, ce qui est d'une
part très inefficace, et d'autre part remultiplie les cas
d'échec.
Ça implique *une* copie, c'est tout. Qu'il l'attrappe par
copie implique une deuxième. Rien devant le coût d'une
exception en général.
Et s'il utilise throw; dans un bloc catch() pour la
relancer ?
Pas de copie, je crois. Je ne suis pas sûr, mais je crois
que le throw sans paramètres est garantie de réutiliser
l'objet existant.
Je me souviens-là des tests que j'ai pu faire lors de la
mise au point d'une classe genre "string", au niveau de
l'opérateur d'affectation et du constructeur de copie (et
en prenant en compte l'instance anonyme transitoire
lorsqu'on retourne un objet entier plutôt qu'un pointeur).
Donc, selon comment cette instance d'exception est
construite, remplie puis "lancée", j'hésite sur le nombre
possible de copies.
Le nombre de copies n'est de toute façon pas bien spécifié.
Conceptuellement, tu construis l'objet « sur la pile » avec
une expression du genre X(), et ensuite, cet objet est copié
ailleurs. Mais un compilateur a le droit de faire en sort
que l'objet temporaire que tu construis, et la copie «
ailleurs », sont en fait le même objet, et supprimer
l'action de copier.
La pire séquece que j'ai pu tracer au debugger était la suivante :
CString ab;
...
ab = CString( "aaaaa") + "bbbbb";
Tout le monde fait ça pour avoir la facilité de l'opérateur de
concaténation, mais bonjour la chaîne d'allocations, copies et
destructions avec libération de mémoire ! Notamment avec le
compilo du VC++6.0, on voit bien la CString anonyme retournée
par operator + C'a m'a tellement révolté que j'ai conçu un
mécanisme permettant à une chaîne de "donner son buffer" et de
se laisser détruire vide, plutôt que de demander à l'autre
d'en prendre copie. Dans l'idiome a = b + c; le gain est
énorme.
Heureusement qu'on peut encore faire de la R&D sérieuse
durant ses loisirs :-D
Figure-toi qu'il y a, aujourd'hui, des boîtes qui savent
estîmer un travail bien fait, et qui sont prêt à donner aux
développeurs ce qu'il faut pour le faire. (Évidemment, elles
n'embauchent pas tous les jours. Mais en cherchant assez
longtemps, on finit par les dénicher.)
Oui, ça devient un métier en soi, surtout quand on n'est pas
assez intégré au réseau pour être connu. C'est pour ça que
j'ai commencé à créer une présence sur le web avec un ami
plutôt commercial, mais ça met du temps à démarrer...
L'innovation fait peut plus qu'elle ne passionne. Et donc
finalement on a davantage envie de monter sa boîte que de
retrouver un employeur.
Patrick 'Zener' Brunet wrote:Je réponds à qui a
écrit : > Patrick 'Zener' Brunet wrote:Je réponds à
[...]Sinon, il faut certainement des classes faites sur mésure
dans l'exception, pour gerer des chaînes sans allocation
dynamique.
Il m'est arrivé de développer de telles classes : elles
sont construites comme des objets globaux, sans allocation
de mémoire dynamique, et donc elles ne sont plus jamais
construites ni détruites : seulement réquisitionnées puis
restituées (elles fournissent une méthode static Throw() ).
Je ne comprends pas trop cette association pas d'allocation
dynamique -- objet global. J'ai bien des objets globaux qui
font de l'allocation dynamique. (J'ai même parfois des
std::string globaux.)
Je veux dire objets globaux **et** ne faisant pas d'allocation
dynamique, afin de n'avoir aucune possiblité d'échec à la
construction.Pour ce qui est de la chaîne message, en fait j'avais
défini un protocole permettant de stocker dans le corps de
l'exception les éléments variants (2 entiers et un tableau
de 127 + 1 caractères), la classe Exception offrant une
fonction type sprintf() contrôlée pour utiliser ça.
Tu n'as pas besoin d'un protocol, parce que tu pourrais
réserver aussi un tableau de caractères dans n'importe
quelle classe dérivée. (Tableau de type, s'entend, pourqu'il
n'y a pas d'allocation dynamique.) Certaines implémentations
des std::exception le font, je crois ; si tu passes un
chaîne plus long que le tableau fixe, elles essaient
d'obtenir de la mémoire dynamique (avec new (nothrow)), et
si ça échoue, elles tronquent la chaîne.
J'ai pris en compte aussi le critère de vitesse,
et par ailleurs j'ai voulu totalement découpler ça de
l'allocation dynamique parce que mes classes travaillent avec
toute une variété de heaps (positionnement et algorithme
d'allocation).
Donc j'ai mis les exception à part. Partant du principe qu'on
n'a pas besoin d'une chaîne volumineuse pour cet usage, j'ai
utilisé une classe à moi qui permet de faire du CString sur un
tableau statique, avec une taille figée (constante de
précompilation). Le pool d'exceptions préallouées ne
représente plus rien dans le contexte d'un logiciel "moderne".
Mais ça n'évite pas totallement le besoin des allocations
dynamique. Le problème, c'est qu'il faut que le système
stocke l'exception même quelque part. Et que ça ne peut pas
être sur la pile, parce qu'elle fait detruire la pile. Et
que ça ne peut pas être en mémoire statique, parce qu'il
peut y avoir d'autres exceptions lors du stack unwinding. (A
propos : comment est-ce qu'on dit « stack unwinding » en
français ?) Alors, l'implémentation est obligée à allouer la
mémoire pour l'exception dynamiquement. (En général,
l'implémentation utilise un tas ou une pile à part pour
ça. Et certainement pas operator new. Mais c'est dynamique
quand même.)
J'ai prévu un pool d'exceptions recyclables, et donc la
fonction Throw en réquisitionne une qui ne le soit pas
déjà. Cela pose évidemment la question de la taille de ce
pool. J'ai opté pour un dimensionnement par constante de
précompilation bien sûr, et comme mes classes sont conçue pour
minimiser les cascades d'échecs (elles font de la récupération
une priorité et donc évitent d'agraver la situation), j'ai
décidé qu'au-delà de 5 exceptions en cours, on dépassait
largement les bornes du raisonnable.
Ca permet donc de justifier ma réponse à la suite...
Sinon pour ce qui est de l'abort(), étant plutôt orienté
informatique-industrielle-sans-renoncement-à-la-mémoire-dynamique,
évidemment c'est hors de question (et donc il faudra que je
me remette un peu au courant des évolutions de la gestion
"optimiste" de mémoire sous Linux depuis 2 ans).
Je suis sceptique en ce qui concerne les possibilités d'un
logiciel critique avec utilisation de la mémoire dynamique.
Critique temps-réel, je pense aussi. Mais sans aller jusque
là, compte tenu du coût et de l'aspect spartiate des systèmes
résolument industriels, il n'est pas rare de confier à un PC
la supervision d'un process avec des contraintes temps-réel
assez fortes.
Nous l'avons fait dans des installations de supervision de tri
ou de préparation de commande par exemple (avec des taux de
l'ordre de 6 transactions par secondes, chacune impliquant un
moulinage de structures en mémoire, des transferts série vers
un automate, réseau vers un AS400, et une ou deux transactions
en base de données genre Sybase ou Oracle. Ca marche très bien
sur un PC correctement dimensionné, mais bien sûr il est hors
de question de jouer ou de surfer sur le net en même temps !
Mais il y a bien des programmes industriels qui ne sont pas
critiques, et qui peuvent supporter un abort, pourvu que la
probabilité ou la fréquence en soit assez faible. (À vrai
dire, tout système critique doit être secouru, aussi. De
façon à ce qu'un crash ne soit pas fatal pour le système
entier.) De toute façon, si tu te bases sur un système
d'exploitation courante, Windows, ou un Unix, il faut
l'accepter, parce qu'ils abortent tous le processus si
l'épuisement de la mémoire se produit lors de
l'agrandissement de la pile.
Pas trop d'accord : s'il y a une exception prévue dans
operator new, ça suppose qu'on devrait avoir une chance d'en
tirer parti, et je me suis donné beaucoup de mal pour ça.
Je sais écrire des applications qui sont conscientes de leurs
ressources et qui savent se récupérer sur des situations
dégradées. Alors bien sûr quand j'ai appris que sous Linux il
y avait un abort() dans le new_handler parce que le système
faisait le béni-oui-oui et tuait des process quand il se
trouvait au pied du mur, évidemment j'ai trouvé ça plutôt ...
NULL. J'espère que ça a évolué.
Il faut savoir aussi que certains process (et pas seulement
dans le domaine de l'I.A.) mettent en jeu des structures âvec
un tel entrelacement de pointeurs, qu'il est peu envisageable
(ou au moins très laborieux) de les reconstruire après un
crash). J'ai dû inventer une technologie pour offrir cette
immunité à un logiciel de la gamme ci-dessus, dans le contexte
d'une éventuelle panne de courant. Ca marche bien même à plein
régime. Mais évidemment si le système se met à faire du
sabordage aléatoire, on n'a plus qu'à chercher un portage
d'Oracle sur rack OS/9 !Aussi, on accepte souvent à prendre la « risque », en
s'assurant qu'il n'y a que l'application en question qui
tourne sur la machine, et que la machine a assez de mémoire
pour ne pas en épuiser.
Sur le genre de système évoqué, ça passe aussi par une bonne
gestion de l'émiettement, c'est ce qui me conduit à utiliser
des heaps spéciaux - et aussi des fichiers, l'expérience
martienne l'a montré :-D2) Votre exception est transmise par copie semble-t-il, et
non par adresse.
Toute exception est transmise par copie. Il le faut bien,
puisqu'on va déballer la pile, et la mémoire où
l'utilisateur le construit (comme temporaire) va
disparaître.
Avec ma convention précédente, justement, c'était un
pointeur vers l'exception qui était transmis, lui donc par
copie en effet.
D'accord. Tu as donc un objet statique, et tu lèves une
exception du type pointeur à l'objet. Seulement, qu'est-ce
qui se passe si les exceptions s'imbriquent, et que tu veux
lever une deuxième exception du même type, alors que la
première est toujours active ? Ou est-ce que tu as conçu
l'application pour que le cas ne peut pas se produire ?
Il y a donc un pool d'exceptions de taille "raisonnable".
Cela implique tout un tas de cycles de
création/copie/destruction de chaînes, ce qui est d'une
part très inefficace, et d'autre part remultiplie les cas
d'échec.
Ça implique *une* copie, c'est tout. Qu'il l'attrappe par
copie implique une deuxième. Rien devant le coût d'une
exception en général.
Et s'il utilise throw; dans un bloc catch() pour la
relancer ?
Pas de copie, je crois. Je ne suis pas sûr, mais je crois
que le throw sans paramètres est garantie de réutiliser
l'objet existant.Je me souviens-là des tests que j'ai pu faire lors de la
mise au point d'une classe genre "string", au niveau de
l'opérateur d'affectation et du constructeur de copie (et
en prenant en compte l'instance anonyme transitoire
lorsqu'on retourne un objet entier plutôt qu'un pointeur).
Donc, selon comment cette instance d'exception est
construite, remplie puis "lancée", j'hésite sur le nombre
possible de copies.
Le nombre de copies n'est de toute façon pas bien spécifié.
Conceptuellement, tu construis l'objet « sur la pile » avec
une expression du genre X(), et ensuite, cet objet est copié
ailleurs. Mais un compilateur a le droit de faire en sort
que l'objet temporaire que tu construis, et la copie «
ailleurs », sont en fait le même objet, et supprimer
l'action de copier.
La pire séquece que j'ai pu tracer au debugger était la suivante :
CString ab;
...
ab = CString( "aaaaa") + "bbbbb";
Tout le monde fait ça pour avoir la facilité de l'opérateur de
concaténation, mais bonjour la chaîne d'allocations, copies et
destructions avec libération de mémoire ! Notamment avec le
compilo du VC++6.0, on voit bien la CString anonyme retournée
par operator + C'a m'a tellement révolté que j'ai conçu un
mécanisme permettant à une chaîne de "donner son buffer" et de
se laisser détruire vide, plutôt que de demander à l'autre
d'en prendre copie. Dans l'idiome a = b + c; le gain est
énorme.
Heureusement qu'on peut encore faire de la R&D sérieuse
durant ses loisirs :-D
Figure-toi qu'il y a, aujourd'hui, des boîtes qui savent
estîmer un travail bien fait, et qui sont prêt à donner aux
développeurs ce qu'il faut pour le faire. (Évidemment, elles
n'embauchent pas tous les jours. Mais en cherchant assez
longtemps, on finit par les dénicher.)
Oui, ça devient un métier en soi, surtout quand on n'est pas
assez intégré au réseau pour être connu. C'est pour ça que
j'ai commencé à créer une présence sur le web avec un ami
plutôt commercial, mais ça met du temps à démarrer...
L'innovation fait peut plus qu'elle ne passionne. Et donc
finalement on a davantage envie de monter sa boîte que de
retrouver un employeur.