OVH Cloud OVH Cloud

destruction d'un Singleton Pattern : Static ou non Static

18 réponses
Avatar
requinham
Bonjour,

je parlais avec un amis sur la declaration de la fonction qui se
chargera de la destruction de notre instance unique destroy()

en fait est ce que c'est n=E9cessaire de la d=E9clarer static au niveau
conceptuel. car au niveau codage elle ne d=E9range pas vue qu'elle sera
la derni=E8re =E0 s'ex=E9cuter donc elle retournera la main =E0 un autre ob=
jet
ou fonction diff=E9rente de l'instance ?

A votre avis comment =E7a se fait ?

8 réponses

1 2
Avatar
Mickaël Wolff
Fabien LE LEZ a écrit :

Ce n'est pas bien méchant.


[...]
En revanche, après le retour de "delete *this", le pointeur "this"
n'est plus valide. Tu ne dois donc plus l'utiliser, explicitement ou
implicitement (en faisant référence à un membre de la classe). Mais à
part ça, tu peux faire tout ce qui te plaît.




Je sais bien, mais ça me pose un problème métaphysique (ou moral).
C'est comme les parenthèses derrière un return ;)

--
Mickaël Wolff aka Lupus Michaelis
http://lupusmic.org
Avatar
Fabien LE LEZ
On Sat, 20 Feb 2010 09:47:44 +0100, Mickaël Wolff
:

Je sais bien, mais ça me pose un problème métaphysique (ou moral).
C'est comme les parenthèses derrière un return ;)



Si tu n'aimes pas les parenthèses, tu n'aimes pas Lisp. En
conséquence, Lisp étant divin, tu n'aimes pas Dieu[*].
Hérétique ! Vade retro Satanas !

Cela dit, je suis d'accord avec toi (mais moi, j'ai le droit, étant
athée). Ce qui me perturbe encore plus, c'est les point-virgules en
trop :
void f() { ... };



[*] ou Vichnou, ou Amaterasu, ou Jupiter, etc. Ne soyons pas
sectaires...
Avatar
Patrick 'Zener' Brunet
Bonsoir.

"Michael Doubez" a écrit dans le message
de news
On 17 fév, 09:02, requinham wrote:
On 17 fév, 09:03, Mickaël Wolff wrote:

requinham a écrit :



en fait est ce que c'est nécessaire de la déclarer static au
niveau conceptuel.





Oui, sinon on risque de se poser des questions sur le pourquoi de
ce fonctionnement.




A vrai dire, le fait de la déclarer static n'a pas de sens car
pouvoir fair un appel statique à destroy n'aura pas de sens tant
qu'il n'y a pas de singleton en memoire et dans le cas où il y en
a on peut l'appeler à partir du singleton exple :
A::getInstance()->destroy() sans problème vue que c'est la
derniere instruction appelé dans la vie du singleton.



Ta question laisse supposer que tu vas appeler toi même la fonction
de destruction du singleton.

AMHA il vaut mieux un traitement générique de la durée de vie du
singleton C'est à dire qu'un singleton hérite d'une interface avec
une fonction membre virtual void destroy(); et qu'une fonction de
netoyage soit en charge de l'appeler au moment de la fin de vie.

Cette solution de permet de distinguer les types de singleton et
leur durée de vie associée à un évènement:
- détruit par le système (pas enregistré auprès d'un gestionnaire
de singleton)
- détruit explicitment à l'exit ou en sortie de scope
- détruit à la sortie d'un thread (pour les singletons TSS)
- détruit quand une dll est déchargée
- ...

Déjà, une fonction de destruction en sortie de programme ( avec
at_exit() ) devrait couvrir la plupart des cas courants et t'évitera
d'avoir à te creuser la tête pour svaoir quand appeler destroy().

Le mieux reste quand même de laisser le système réclamer les
ressources - si c'est possible.



Cette discussion me rappelle celle-ci, qui faisait intervenir un problème
parasite et très génant: l'ordre d'assemblage des modules objets par le
linker:
http://tinyurl.com/yjng66e (alias pour)
http://groups.google.com/group/fr.comp.lang.c++/browse_thread/thread/e5e8788
1453053d2/42e34475bd490e9d

...avec finalement impossibilité de compter même sur atexit().

Quand à renoncer à restituer les ressources pour laisser le système les
reprendre, au-delà du côté frustrant, je ne suis pas sûr que le système
puisse tout "fermer" proprement. Ca dépend de la nature des ressources, en y
incluant le fonctionnel que l'on implémente:
Il va reprendre la mémoire, déclarer abandonnés les mutexes et autres objets
system-wide,
...fermer les fichiers ouverts (mais sans flush a priori),
...mais il peut y avoir d'autres éléments fonctionnels codés dans les
destructeurs des objets représentant l'application, et qui ne seront pas
traités (par exemple: écrire un épilogue dans un fichier avant de le fermer,
envoyer une trame "bye" dans une connexion, écrire un log, etc.)

Bref, je persiste à penser qu'un last-event exploitable dans le processus
fait cruellement défaut.

--
Cordialement.

* Patrick BRUNET www.ipzb.fr www.ipzb-pro.com
* E-mail: lien sur http://zener131.eu/ContactMe
Avatar
James Kanze
On 22 Feb, 23:24, "Patrick 'Zener' Brunet"
wrote:
Bonsoir.
"Michael Doubez" a écrit dans le message
de news
> On 17 fév, 09:02, requinham wrote:
>> On 17 fév, 09:03, Mickaël Wolff wrote:



[...]
> Cette solution de permet de distinguer les types de singleton et
> leur durée de vie associée à un évènement:
> - détruit par le système (pas enregistré auprès d'un gestionn aire
> de singleton)
> - détruit explicitment à l'exit ou en sortie de scope
> - détruit à la sortie d'un thread (pour les singletons TSS)
> - détruit quand une dll est déchargée
> - ...



> Déjà, une fonction de destruction en sortie de programme ( avec
> at_exit() ) devrait couvrir la plupart des cas courants et t'évitera
> d'avoir à te creuser la tête pour svaoir quand appeler destroy().



> Le mieux reste quand même de laisser le système réclamer les
> ressources - si c'est possible.



Cette discussion me rappelle celle-ci, qui faisait intervenir
un problème parasite et très génant: l'ordre d'assemblage des
modules objets par le linker:http://tinyurl.com/yjng66e
(alias
pour)http://groups.google.com/group/fr.comp.lang.c++/browse_thread/thread /...
1453053d2/42e34475bd490e9d



...avec finalement impossibilité de compter même sur atexit().



Quand à renoncer à restituer les ressources pour laisser le
système les reprendre, au-delà du côté frustrant, je ne suis
pas sûr que le système puisse tout "fermer" proprement. Ca
dépend de la nature des ressources, en y incluant le
fonctionnel que l'on implémente:
Il va reprendre la mémoire, déclarer abandonnés les mutexes et
autres objets system-wide,
...fermer les fichiers ouverts (mais sans flush a priori),
...mais il peut y avoir d'autres éléments fonctionnels codés
dans les destructeurs des objets représentant l'application,
et qui ne seront pas traités (par exemple: écrire un épilogue
dans un fichier avant de le fermer, envoyer une trame "bye"
dans une connexion, écrire un log, etc.)



Bref, je persiste à penser qu'un last-event exploitable dans
le processus fait cruellement défaut.



Le problème, c'est qu'il n'y a pas de solution possible du
problème. Que faire, par exemple, si écrire l'épilogue a besoin
d'autres ressources qui pourraient déjà avoir été libérées ? Il
peut y avoir des dépendences que ni le système ni le compilateur
ne peuvent savoir.

--
James Kanze
Avatar
Patrick 'Zener' Brunet
Bonsoir.

"James Kanze" a écrit dans le message
de news
On 22 Feb, 23:24, "Patrick 'Zener' Brunet"
wrote:
Bonsoir.
"Michael Doubez" a écrit dans le message
de news

On 17 fév, 09:02, requinham wrote:
On 17 fév, 09:03, Mickaël Wolff
wrote:







[...]
Cette solution de permet de distinguer les types de singleton et
leur durée de vie associée à un évènement:
- détruit par le système (pas enregistré auprès d'un
gestionnaire de singleton)
- détruit explicitment à l'exit ou en sortie de scope
- détruit à la sortie d'un thread (pour les singletons TSS)
- détruit quand une dll est déchargée
- ...





Déjà, une fonction de destruction en sortie de programme ( avec
at_exit() ) devrait couvrir la plupart des cas courants et
t'évitera d'avoir à te creuser la tête pour svaoir quand appeler
destroy().





Le mieux reste quand même de laisser le système réclamer les
ressources - si c'est possible.





Cette discussion me rappelle celle-ci, qui faisait intervenir
un problème parasite et très génant: l'ordre d'assemblage des
modules objets par le linker:


> http://tinyurl.com/yjng66e
(alias





pour)http://groups.google.com/group/fr.comp.lang.c++/browse_thread/thread/..
.
1453053d2/42e34475bd490e9d



...avec finalement impossibilité de compter même sur atexit().



Quand à renoncer à restituer les ressources pour laisser le
système les reprendre, au-delà du côté frustrant, je ne suis
pas sûr que le système puisse tout "fermer" proprement. Ca
dépend de la nature des ressources, en y incluant le
fonctionnel que l'on implémente:
Il va reprendre la mémoire, déclarer abandonnés les mutexes et
autres objets system-wide,
...fermer les fichiers ouverts (mais sans flush a priori),
...mais il peut y avoir d'autres éléments fonctionnels codés
dans les destructeurs des objets représentant l'application,
et qui ne seront pas traités (par exemple: écrire un épilogue
dans un fichier avant de le fermer, envoyer une trame "bye"
dans une connexion, écrire un log, etc.)



Bref, je persiste à penser qu'un last-event exploitable dans
le processus fait cruellement défaut.



Le problème, c'est qu'il n'y a pas de solution possible du
problème. Que faire, par exemple, si écrire l'épilogue a besoin
d'autres ressources qui pourraient déjà avoir été libérées ? Il
peut y avoir des dépendences que ni le système ni le compilateur
ne peuvent savoir.



Certes! Ca va être un peu long, mais j'aime la précision.

Moi ce que je voudrais, c'est avoir une chance de dépiler proprement ce que
*moi* j'ai pu construire dans l'ordre inverse.
Je pense en effet qu'il est malsain de compter sur le système et le compilo
pour deviner, et donc que le développeur doit aller jusqu'au bout de ce
qu'il implémente et dont il maîtrise la logique.
Avec un déclencheur adéquat, on pourrait le faire.

Par exemple, si je disposais d'une callback genre atexit() et de la garantie
qu'elle est invoquée juste avant l'exit du process, c'est à dire *après le
dernier destructeur d'objet global*, incluant ceux de l'utilisateur, je
pourrais m'en servir.
Je pourrais par exemple utiliser des globales non-objects pour conserver les
derniers états de mes ressources internes au process, et cette callback
ferait le ménage à partir de ces infos avant qu'elles ne soient dégagées
avec tout l'espace du process.

Je considère que dans une bonne logique de dépendances, les ressources
externes attachées au process devraient être encore valides à ce moment, le
système ne les reprenant qu'après avoir désalloué le process.
Bien sûr, si le process doit être tué, il est fort possible que certaines de
ces ressources soient en erreur (notamment un canal de communication etc.),
mais ça le process est supposé capable de le gérer (moi du moins j'y pense
quand je code).
Mais une telle erreur fonctionnelle c'est différent d'un espace mémoire
désalloué prématurément.
Ce que je "réclame", c'est un last event exploitable pour la vie
fonctionnelle du process, et qui soit utilisable depuis l'intérieur d'une
librairie à linkage statique, puisque je suis dans le contexte du
fournisseur d'outils.

Faute de ce déclencheur ultime, je procède ainsi avec les destructeurs (voir
la conversation citée pour le contexte, en résumé c'est un "heap manager"
qui présente sous une abstraction homogène plusieurs heaps, dont le heap par
défaut):

- Comme je ne peux pas espérer que le HeapManager (un objet global) soit
construit en premier, en fait il est représenté par un objet squelette (dont
le constructeur ne fait rien) contenant un pointeur global vers le véritable
HeapManager, qu'il construit à la première tentative d'utilisation...
Ca c'est faisable grâce à la préinitialisation des static non-objets.

En fait il y a toujours un first event pour le HM: au plus tard le premier
appel à ses services.
Contrairement à la fin d'utilisation qui est un non-événement, et ne
pourrait être détecté que par un système de lock-count, rendant la librairie
dépendante de son utilisateur en termes de fiabilité...
Donc le problème c'est cette fin de vie, dans le cas où le HM est détruit
alors que certains objets globaux de l'utilisateur qui le référencent ne le
seront qu'ensuite.

- Comme je ne peux pas compter que le HM soit détruit en dernier, en fait le
destructeur du squelette fait le ménage des ressources, et ensuite le
squelette subsiste en mode "fin de vie" afin de gérer les appels de méthodes
qui peuvent encore survenir, et qui deviennent des no-ops.
Notamment ça désactive les traces et autres assertions pour cette fin de
vie, ce qui leur permet d'exister pour avant et donc de permettre de blinder
le code.

J'arrive à sortir du process sans me prendre en mode debug un rapport
d'erreur m'accusant de memory leaks, ce qui est toujours du meilleur effet
quand on veut livrer une librairie, pas vrai ?

C'est pas très sexy, mais je gère ainsi une bonne partie de mon problème
sans compter sur l'utilisateur.
Avec un tel last event je pourrais tout gérer proprement.

J'ai beau chercher, je ne vois pas de bonne raison (au sens fonctionnel)
pour qu'une callback de atexit() puisse être intercalée entre les
destructeurs d'objets globaux dans le démontage final.
D'un point de vue technique, si je comprends bien que l'ordre des
constructeurs et des destructeurs obéit à des contraintes résolues à la
compilation et qui le rendent difficilement reconsidérable au moment du
link,
...par contre il me semble que la(les) callback(s) atexit() sont indexées
dans une table, et donc pourraient assez facilement être regroupées à la
vraie fin du process.

D'accord, c'est du perfectionnisme.
A ce stade je rappelle volontiers cette citation de G.B. Shaw sur l'homme
raisonnable et le déraisonnable :-)

--
Cordialement.

* Patrick BRUNET www.ipzb.fr www.ipzb-pro.com
* E-mail: lien sur http://zener131.eu/ContactMe
Avatar
James Kanze
On Mar 2, 10:18 pm, "Patrick 'Zener' Brunet"
wrote:

"James Kanze" a écrit dans le message
de news m



> On 22 Feb, 23:24, "Patrick 'Zener' Brunet"
> wrote:
>> Bonsoir.
>> "Michael Doubez" a écrit dans le message
>> de news
>>
>>> On 17 fév, 09:02, requinham wrote:
>>>> On 17 fév, 09:03, Mickaël Wolff
>>>> wrote:



> [...]
>>> Cette solution de permet de distinguer les types de singleton et
>>> leur durée de vie associée à un évènement:
>>> - détruit par le système (pas enregistré auprès d'un
>>> gestionnaire de singleton)
>>> - détruit explicitment à l'exit ou en sortie de scope
>>> - détruit à la sortie d'un thread (pour les singletons TSS)
>>> - détruit quand une dll est déchargée
>>> - ...



>>> Déjà, une fonction de destruction en sortie de programme ( avec
>>> at_exit() ) devrait couvrir la plupart des cas courants et
>>> t'évitera d'avoir à te creuser la tête pour svaoir quand appele r
>>> destroy().



>>> Le mieux reste quand même de laisser le système réclamer les
>>> ressources - si c'est possible.



>> Cette discussion me rappelle celle-ci, qui faisait intervenir
>> un problème parasite et très génant: l'ordre d'assemblage des
>> modules objets par le linker:
> >http://tinyurl.com/yjng66e
>> (alias



pour)http://groups.google.com/group/fr.comp.lang.c++/browse_thread/thread /..
.



>> 1453053d2/42e34475bd490e9d



>> ...avec finalement impossibilité de compter même sur atexit().



>> Quand à renoncer à restituer les ressources pour laisser le
>> système les reprendre, au-delà du côté frustrant, je ne suis
>> pas sûr que le système puisse tout "fermer" proprement. Ca
>> dépend de la nature des ressources, en y incluant le
>> fonctionnel que l'on implémente:
>> Il va reprendre la mémoire, déclarer abandonnés les mutexes et
>> autres objets system-wide,
>> ...fermer les fichiers ouverts (mais sans flush a priori),
>> ...mais il peut y avoir d'autres éléments fonctionnels codés
>> dans les destructeurs des objets représentant l'application,
>> et qui ne seront pas traités (par exemple: écrire un épilogue
>> dans un fichier avant de le fermer, envoyer une trame "bye"
>> dans une connexion, écrire un log, etc.)



>> Bref, je persiste à penser qu'un last-event exploitable dans
>> le processus fait cruellement défaut.



> Le problème, c'est qu'il n'y a pas de solution possible du
> problème. Que faire, par exemple, si écrire l'épilogue a besoin
> d'autres ressources qui pourraient déjà avoir été libérées ? Il
> peut y avoir des dépendences que ni le système ni le compilateur
> ne peuvent savoir.



Certes! Ca va être un peu long, mais j'aime la précision.



Moi ce que je voudrais, c'est avoir une chance de dépiler
proprement ce que *moi* j'ai pu construire dans l'ordre
inverse.



Ça, tu l'as. Tu lèves une exception, que tu attrappes dans main,
et tout ce qu'il y a sur la pile sera dépilé. Dans l'ordre
inverse de la construction. Ce sont les objets dont on a besoin
dans les constructeurs et les destructeurs des objects à durée
de vie statique qui posent un problème.

Je pense en effet qu'il est malsain de compter sur le système
et le compilo pour deviner, et donc que le développeur doit
aller jusqu'au bout de ce qu'il implémente et dont il maîtrise
la logique. Avec un déclencheur adéquat, on pourrait le
faire.



Par exemple, si je disposais d'une callback genre atexit() et
de la garantie qu'elle est invoquée juste avant l'exit du
process, c'est à dire *après le dernier destructeur d'objet
global*, incluant ceux de l'utilisateur, je pourrais m'en
servir.



Oui et non. Tu auras toujours le problème de l'ordre des appels
quand il y a eu plusieurs fonctions enrégistrées. Et que faire
si la fonction enrégistrée a besoin d'un objet statique.

[...]
J'ai beau chercher, je ne vois pas de bonne raison (au sens fonctionnel)
pour qu'une callback de atexit() puisse être intercalée entre les
destructeurs d'objets globaux dans le démontage final.



La raison principale, je crois, c'est pour que l'appel des
destructeurs puisse être géré par la logique d'atexit. Quand le
code de démarrage revient de l'appel d'un constructeur, il
enrégistre une fonction qui appelle le destructeur avec atexit.

--
James Kanze
Avatar
Patrick 'Zener' Brunet
Bonsoir.

"James Kanze" a écrit dans le message
de news
On Mar 2, 10:18 pm, "Patrick 'Zener' Brunet"
wrote:

"James Kanze" a écrit dans le message
de news




On 22 Feb, 23:24, "Patrick 'Zener' Brunet"
wrote:
Bonsoir.
"Michael Doubez" a écrit dans le message
de news

On 17 fév, 09:02, requinham wrote:
On 17 fév, 09:03, Mickaël Wolff
wrote:











[...]



Moi ce que je voudrais, c'est avoir une chance de dépiler
proprement ce que *moi* j'ai pu construire dans l'ordre
inverse.



Ça, tu l'as. Tu lèves une exception, que tu attrappes dans main,
et tout ce qu'il y a sur la pile sera dépilé. Dans l'ordre
inverse de la construction. Ce sont les objets dont on a besoin
dans les constructeurs et les destructeurs des objects à durée
de vie statique qui posent un problème.




Oui, tout à fait.
Navré, j'ai embrouillé les pistes en parlant de "dépiler". Je voulais dire
"démonter", dans l'ordre inverse pour respecter les dépendances, et bien sûr
il s'agit des objets globaux.

Je pense en effet qu'il est malsain de compter sur le système
et le compilo pour deviner, et donc que le développeur doit
aller jusqu'au bout de ce qu'il implémente et dont il maîtrise
la logique. Avec un déclencheur adéquat, on pourrait le
faire.



Par exemple, si je disposais d'une callback genre atexit() et
de la garantie qu'elle est invoquée juste avant l'exit du
process, c'est à dire *après le dernier destructeur d'objet
global*, incluant ceux de l'utilisateur, je pourrais m'en
servir.



Oui et non. Tu auras toujours le problème de l'ordre des appels
quand il y a eu plusieurs fonctions enrégistrées. Et que faire
si la fonction enrégistrée a besoin d'un objet statique.




Dans la logique que j'exposais, je m'attendrais (même si ça ce marche pas,
objet du débat) à ce qu'en tant que last-event, elle soit appelée durant
l'exit, après le dernier destructeur d'objet global.
Et donc logiquement elle ne devrait plus toucher à ces objets. Par contre
elle pourrait démanteler un objet construit sur le heap et attaché à un
pointeur static, c'est la solution de repli que j'espérais.
Plusieurs callbacks atexit() enregistrées ? Et bien en toute logique elles
devraient être invoquées dans l'ordre inverse, ce qui serait parfait pour
moi.
D'ailleurs pour déclencher proprement les destructeurs, cet ordre inverse
doit être respecté a priori.

Sauf que le mix avec les destructeurs fausse tout, mais tu donnes
l'explication ci-dessous:

[...]
J'ai beau chercher, je ne vois pas de bonne raison (au sens
fonctionnel) pour qu'une callback de atexit() puisse être
intercalée entre les destructeurs d'objets globaux dans le
démontage final.



La raison principale, je crois, c'est pour que l'appel des
destructeurs puisse être géré par la logique d'atexit. Quand le
code de démarrage revient de l'appel d'un constructeur, il
enrégistre une fonction qui appelle le destructeur avec atexit.



Berk Berk Beuâârk ! voilà qui explique tout !

Si le framework commence à utiliser lui-même les quelques primitives qu'il
laisse à l'Utilisateur et les contraint de la sorte, évidemment ça coince
bien
Pourtant il y a un moment que les compilos C++ ne passent plus par une
conversion en C.
Fâcheuse interaction àmha: l'API Utilisateur c'est rien que pour
l'Utilisateur.

OK, et bien je pense que la solution que j'ai déployée est le mieux que je
pouvais espérer avec du C++.
C'est vraiment pas simple de dépasser le développement applicatif et faire
du pratique et robuste à la fois.

Merci pour tes lumières sur les aspects inside.

--
Cordialement.

* Patrick BRUNET www.ipzb.fr www.ipzb-pro.com
* E-mail: lien sur http://zener131.eu/ContactMe
Avatar
James Kanze
On 5 Mar, 20:16, "Patrick 'Zener' Brunet"
wrote:

[...]
Dans la logique que j'exposais, je m'attendrais (même si ça ce marche pas,
objet du débat) à ce qu'en tant que last-event, elle soit appelée d urant
l'exit, après le dernier destructeur d'objet global.
Et donc logiquement elle ne devrait plus toucher à ces objets. Par cont re
elle pourrait démanteler un objet construit sur le heap et attaché à un
pointeur static, c'est la solution de repli que j'espérais.
Plusieurs callbacks atexit() enregistrées ? Et bien en toute logique el les
devraient être invoquées dans l'ordre inverse, ce qui serait parfait pour
moi.
D'ailleurs pour déclencher proprement les destructeurs, cet ordre inver se
doit être respecté a priori.

Sauf que le mix avec les destructeurs fausse tout,



Quoiqu'il fasse, il y aura des mécontents. D'autres vont vouloir
que toutes les fonctions enrégistrées dans atexit puisse aussi
utiliser les objets statiques. Il faudrait un atexit pour avant
les déstructeurs, et un atexit pour après. (Mais c'est vrai que
les règles actuelles ne peuvent résoudre des problèmes de
personne, puisqu'on arrive toujours au même résultat avec une
variable statique locale.)

mais tu donnes l'explication ci-dessous:

> [...]
>> J'ai beau chercher, je ne vois pas de bonne raison (au sens
>> fonctionnel) pour qu'une callback de atexit() puisse être
>> intercalée entre les destructeurs d'objets globaux dans le
>> démontage final.

> La raison principale, je crois, c'est pour que l'appel des
> destructeurs puisse être géré par la logique d'atexit. Quand le
> code de démarrage revient de l'appel d'un constructeur, il
> enrégistre une fonction qui appelle le destructeur avec atexit.

Berk Berk Beuâârk ! voilà qui explique tout !

Si le framework commence à utiliser lui-même les quelques
primitives qu'il laisse à l'Utilisateur et les contraint de la
sorte, évidemment ça coince bien Pourtant il y a un moment que
les compilos C++ ne passent plus par une conversion en C.
Fâcheuse interaction àmha: l'API Utilisateur c'est rien que
pour l'Utilisateur.



Dans le contexte historique, il s'agissait d'implémenter le C++
le plus simplement possible, avec les moyens du bord; dans ce
contexte, la solution adoptée me semble justifiée (et que la
spécification ne garantit rien en ce qui concerne l'ordre
rélatif, ce qui d'après mes souvenirs était le cas dans les
premières versions de C++ sorties de Bell Labs). Que la norme
ait canonisé cette solution, c'est une autre question. Dans
l'ensemble, je pense un peu comme toi.

--
James Kanze
1 2