Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

initialisation des variables membres par défaut

73 réponses
Avatar
Richard Delorme
// ---------8<----------------------------
#include <iostream>

class A {
private:
int x;

public:
A() {};
~A() {};
void print() {
std::cout << x << std::endl;
}
};


int main() {
A t;
int y;


t.print();
std::cout << y << std::endl;

return 0;
}
// ---------8<----------------------------

Dans l'exemple ci-dessus, ni x, membre de la classe A, ni la variable
locale y ne sont initialisées.
gcc détecte le cas de la variable locale :
attention : ‘y’ may be used uninitialized in this function
mais reste silencieux sur la variable membre.
Valgrind signale les deux cas (de manière guère compréhensible d'ailleurs).

Personnellement je pensais comme Valgrind que la variable x devait être
initialisé explicitement dans le constructeur, par exemple en écrivant :
A() : x() {};
à la place du constructeur ci-dessus.

Néanmoins la lecture de blogs sur internet me laisse dans le doute. Par
exemple ici :
http://discuss.joelonsoftware.com/default.asp?joel.3.489111.50

On lit tout et son contraire. Qu'en est il en pratique ? (et en théorie
aussi d'ailleurs).

--
Richard

10 réponses

Avatar
Richard Delorme
Le 27/01/2010 09:17, Wykaaa a écrit :
Richard Delorme a écrit :
Le 26/01/2010 19:35, Marc Espie a écrit :
In article<4b5f22b7$0$17500$,
Richard Delorme wrote:
La réalité peut être plus complexe. En pratique une classe peut-être
assez compliquée et n'avoir besoin que d'une partie de ses variables
initialisées selon la situation. Tout initialiser dans le constructeur
(ou pire, avoir un compilateur qui initialiserait tout par défaut) peut
causer des problèmes de performances. L'idéal est de n'initialiser que
ce qui est nécessaire avant son utilisation.




Ca pue (au sens anti-pattern). Si ta classe est assez complexe pour
pouvoir tomber sur ce genre de choses, c'est generalement que tu
essaies de
lui faire faire trop de choses, et qu'elle gagnerait grandement a etre
decoupee en morceaux plus petits, pour lesquels ce genre de souci ne se
poserait plus.





Entièrement d'accord avec toi.

Pas nécessairement. Je prend un exemple, un coup dans un jeu d'échec.
Une implémentation simplifiée sous forme de classe pourrait être :

class Move {
// fonctions membres privées
public:
struct {
Coordinate x;
Piece piece;
} from, to;
Piece promotion;
int value;

// fonctions membres publiques.
}
Pourquoi initialiser la variable promotion si la pièce de départ n'est
pas un pion, où, même si c'est un pion, la case d'arrivée n'est pas
sur la dernière rangée ?



Cette classe en fait déjà trop. Pourquoi mélanger le coup avec la
promotion ?



Parce que, conceptuellement, la promotion est un attribut du coup.

La valeur du coup, la variable value, est issue d'un long calcul. A
quoi bon y mettre une valeur bidon ?



Si, à l'initialisation d'une instance de classe, il y a des attributs
qu'on ne sait pas initialiser dans le constructeur, c'est qu'il y a un
défaut de conception.



Pour "value" je fais comment? Pour moi la mauvaise réflexion est de ce
demander si je vais pouvoir initialiser (autrement qu'avec une valeur
bidon) une variable pour décider de la rendre membre ou non. C'est ce
focaliser sur un dogme qui ne fait pas partie du langage mais juste une
opinion sur ce qu'est une hypothétique bonne conduite. Moi je préfère
être pragmatique. Mes coups, aux échecs, je les note. Cette note est
pour moi, indépendamment de tout langage de programmation un attribut du
coup. donc elle doit faire partie de la classe Move.

C'est le cas de ta classe Move car "promotion" ne
doit pas se trouver là.



Ah et ou ça alors ?
En notation algébrique standard (SAN) on écrit p.ex., hxg1=Q. Si je doit
lire un tel coup, il faut bien que je stocke le =Q quelque part ?
Maintenant si le coup est Qd4, la promotion n'a pas de sens. Ma fonction
pour lire de tel coup se présente comme ça :
void Move::from_SAN(std::istream &is, const Board &board);
et à l'usage c'est juste un move.from_SAN(is, board); qu'il y ait un
coup avec ou sans promotion, m'importe peu. Si je met la promotion
ailleurs, je ne vois pas comment lire ce coup de manière aussi simple.

Pour moi, l'état indéterminée d'une variable a du sens et je ne
comprends pas cette volonté de mettre une valeur déterminée à tout prix
pour tout.



Non, il n'y a aucun sens à avoir des variables avec un état indéterminé.



Si, ça représente un état de connaissance partiel des membres de la classe.

C'est forcément le signe d'un défaut de conception quelque part.



Non.

En pratique, cette classe ne contient ni constructeur ni destructeur.



C'est déjà mauvais signe.

Les données du coup sont initialisées directement depuis son conteneur
(un tableau de coups), car il est plus simple de générer l'ensemble
des coups (ou tout du moins d'une famille de coups), qu'un coup isolé.



D'accord mais ce n'est pas parce que l'on va faire comme ça que la
classe qui décrit 1 coup ne doit pas avoir de constructeur pour
initialiser ses propres attributs.



Si, parce que ça je ne sais pas initialiser un coup seul de manière
efficace. Je peux y mettre des valeurs bidons, mais en dehors d'une
perte de temps, je n'en vois pas l'intérêt.

Peut-être cette façon de procéder est-elle un anti-pattern, mais c'est
la manière idiomatique qu'utilise tous les programmes d'un niveau
acceptable écrit en C++.



Ton exemple est totalement anti-pattern, effectivement.



Je n'en suis pas sûr. Une conception inefficace en terme de performance
est un anti-pattern.

Ce n'est pas parce que la plupart des programmes C++ sont mal écrits
(mettons au moins 90%) qu'il faut justifier cette manière de faire.



On n'a pas la même définition de programmes mal écrits.

--
Richard
Avatar
Richard Delorme
Le 27/01/2010 15:33, Stan a écrit :

Sinon, pour en revenir aux points que tu as soulevés, j'aimerai bien
que tu me dises
quels sont les paradigmes C++ que tu _utilises_ dans un programme de
jeux d'échecs,
parce que j'ai l'impression que l'aspect performance limite pas mal
les choses
( quid des conteners ?).



J'utilise pas mal d'énumération (qui ont un typage plus fort qu'en C).
De la programmation objet, j'utilise l'encapsulation, et c'est à peu
prêt tout. Pas d'héritage non que je soit contre, mais je n'en ai pas
d'usage.
La gestion des erreurs par try/catch (en particulier sur tout ce qui est
entrée par l'utilisateur (ou depuis un fichier, une interface graphique,
etc.).
Les I/O et les strings du C++.
Le RAII par endroit.
Les conteneurs de la bibliothèque standard, j'en ai utilisé au début
(prototypage plus rapide), mais il ne doit plus rien rester,
effectivement pour des questions de performances.
Quelque template, mais ça reste rare.
Je n'utilise a peu prêt rien de la bibliothèque du langage C, sauf les
assertions (test des préconditions et des post-conditions) et ce qui est
inévitable (thread, gestion du temps, etc.), mais en encapsulant ça dans
des classes C++.
J'utilise new/delete, mais tout est alloué au début du programme et
détruit en fin de programme. Il ne doit y avoir que très peu d'autres
allocations (et en tout cas aucune dans les parties sensibles à la
performance).
Pour faire simple, j'utilise le C++ comme il y a 15 ans, à quelques
exceptions prêts.

Un programme d'échecs assez intéressant est "fruit (de Fabien Letouzey)
" qui utilise le C++ comme un "better C" et sa surchage de fonctions.
Pas de classes, pas d'I/O C++, etc.

Sur les forums d'échecs, la question du "meilleur langage" revient
souvent et les vertus/défauts du C++ y sont souvent débattus :
http://talkchess.com/forum/viewtopic.php?p11921#311921
http://talkchess.com/forum/viewtopic.php?p%7552#257552

--
Richard
Avatar
espie
In article <4b5fded2$0$928$,
Richard Delorme wrote:
Le 26/01/2010 19:35, Marc Espie a écrit :
Ca pue (au sens anti-pattern). Si ta classe est assez complexe pour
pouvoir tomber sur ce genre de choses, c'est generalement que tu essaies de
lui faire faire trop de choses, et qu'elle gagnerait grandement a etre
decoupee en morceaux plus petits, pour lesquels ce genre de souci ne se
poserait plus.



Pas nécessairement. Je prend un exemple, un coup dans un jeu d'échec.
Une implémentation simplifiée sous forme de classe pourrait être :

class Move {
// fonctions membres privées
public:
struct {
Coordinate x;
Piece piece;
} from, to;
Piece promotion;
int value;

// fonctions membres publiques.
}

Pourquoi initialiser la variable promotion si la pièce de départ n'est
pas un pion, où, même si c'est un pion, la case d'arrivée n'est pas sur
la dernière rangée ?
La valeur du coup, la variable value, est issue d'un long calcul. A quoi
bon y mettre une valeur bidon ?



Merci d'apporter de l'eau a mon moulin en donnant un exemple ou la
conception n'est clairement pas finie. Tu as un truc qui est Move + value,
ici, et qui devrait donc s'appuyer sur un class Move.

Ta definition de Move est bizarre, je comprend tres bien le Coordinate,
mais pourquoi piece de depart et piece d'arrivee ? tu modelises les
captures ?

Ou sont les roques dans tout ca ?

Rien que le fait d'avoir un attribut qui sera parfois defini, mais pas
toujours, ca tendrait a indiquer que tu devrais avoir une class abstraite
Move, avec plusieurs sous-classes possedant eventuellement des attributs
differents. Tu vas me dire, performance, mais je ne suis meme pas convaincu
avant d'avoir explicitement fait le test.

J'aurais envie de repondre design semi-objet pas fini, avec encore une
grosse dose de procedural.

Les variables non initialisees (et leur copain, les switch sur un champ type)
sont des symptomes de design faits par des gens qui n'ont pas encore bien
integre la conception objet (ou qui, pour de basses questions de temps,
n'ont pas termine leur design).
Avatar
Fabien LE LEZ
On Wed, 27 Jan 2010 07:33:25 +0100, Richard Delorme
:

Piece promotion;



Est-ce qu'un Faillible<Piece> ne serait pas mieux ici, puisque
promotion n'est pas forcément valide ?
Avatar
Richard Delorme
Le 27/01/2010 17:11, Marc Espie a écrit :
In article<4b5fded2$0$928$,
Richard Delorme wrote:
Le 26/01/2010 19:35, Marc Espie a écrit :
Ca pue (au sens anti-pattern). Si ta classe est assez complexe pour
pouvoir tomber sur ce genre de choses, c'est generalement que tu essaies de
lui faire faire trop de choses, et qu'elle gagnerait grandement a etre
decoupee en morceaux plus petits, pour lesquels ce genre de souci ne se
poserait plus.



Pas nécessairement. Je prend un exemple, un coup dans un jeu d'échec.
Une implémentation simplifiée sous forme de classe pourrait être :

class Move {
// fonctions membres privées
public:
struct {
Coordinate x;
Piece piece;
} from, to;
Piece promotion;
int value;

// fonctions membres publiques.
}

Pourquoi initialiser la variable promotion si la pièce de départ n'est
pas un pion, où, même si c'est un pion, la case d'arrivée n'est pas sur
la dernière rangée ?
La valeur du coup, la variable value, est issue d'un long calcul. A quoi
bon y mettre une valeur bidon ?



Merci d'apporter de l'eau a mon moulin en donnant un exemple ou la
conception n'est clairement pas finie. Tu as un truc qui est Move + value,
ici, et qui devrait donc s'appuyer sur un class Move.



Je ne comprend pas cette remarque.

Ta definition de Move est bizarre, je comprend tres bien le Coordinate,
mais pourquoi piece de depart et piece d'arrivee ? tu modelises les
captures ?



Oui. A minima, les informations nécessaire pour un coup sont la case
d'arrivée, de départ et le type de promotion. Si l'on dispose de
l'échiquier ça suffit pour jouer un coup. Si l'on souhaite pouvoir faire
d'autres choses (trier les coups sans échiquier, revenir en arrière,
etc.), c'est pratique d'avoir un peu plus d'information.

Ou sont les roques dans tout ca ?



Le roque c'est juste un roi qui bouge de deux cases.

Rien que le fait d'avoir un attribut qui sera parfois defini, mais pas
toujours, ca tendrait a indiquer que tu devrais avoir une class abstraite
Move, avec plusieurs sous-classes possedant eventuellement des attributs
differents. Tu vas me dire, performance, mais je ne suis meme pas convaincu
avant d'avoir explicitement fait le test.



C'est possible.

J'aurais envie de repondre design semi-objet pas fini, avec encore une
grosse dose de procedural.



Les variables non initialisees (et leur copain, les switch sur un champ type)
sont des symptomes de design faits par des gens qui n'ont pas encore bien
integre la conception objet (ou qui, pour de basses questions de temps,
n'ont pas termine leur design).



Ou qui ont axé la priorité sur d'autres parties du code...

--
Richard
Avatar
Wykaaa
Richard Delorme a écrit :
Le 27/01/2010 15:33, Stan a écrit :

Sinon, pour en revenir aux points que tu as soulevés, j'aimerai bien
que tu me dises
quels sont les paradigmes C++ que tu _utilises_ dans un programme de
jeux d'échecs,
parce que j'ai l'impression que l'aspect performance limite pas mal
les choses
( quid des conteners ?).



J'utilise pas mal d'énumération (qui ont un typage plus fort qu'en C).
De la programmation objet, j'utilise l'encapsulation, et c'est à peu
prêt tout. Pas d'héritage non que je soit contre, mais je n'en ai pas
d'usage.
La gestion des erreurs par try/catch (en particulier sur tout ce qui est
entrée par l'utilisateur (ou depuis un fichier, une interface graphique,
etc.).
Les I/O et les strings du C++.
Le RAII par endroit.
Les conteneurs de la bibliothèque standard, j'en ai utilisé au début
(prototypage plus rapide), mais il ne doit plus rien rester,
effectivement pour des questions de performances.
Quelque template, mais ça reste rare.
Je n'utilise a peu prêt rien de la bibliothèque du langage C, sauf les
assertions (test des préconditions et des post-conditions) et ce qui est
inévitable (thread, gestion du temps, etc.), mais en encapsulant ça dans
des classes C++.
J'utilise new/delete, mais tout est alloué au début du programme et
détruit en fin de programme. Il ne doit y avoir que très peu d'autres
allocations (et en tout cas aucune dans les parties sensibles à la
performance).
Pour faire simple, j'utilise le C++ comme il y a 15 ans, à quelques
exceptions prêts.



Il y a 15 ans on utilisait plusss que seulement l'encapsulation en C++,
surtout si on avait une réel approche objet.

Un programme d'échecs assez intéressant est "fruit (de Fabien Letouzey)
" qui utilise le C++ comme un "better C" et sa surchage de fonctions.
Pas de classes, pas d'I/O C++, etc.



J'ai toujours dit à mes clients (en tant que consultant) et à mes
auditeurs (en tant que formateur) qu'utiliser C++ pour programmer dans
un style "à la C" était plus néfaste que de rester en C (à cause de la
maintenance, pas des performances).
Programmer en C++ sans utiliser les classes, excuse-moi, mais c'est
carrément stupide. Si c'est principalement pour la surcharge de
fonctions, c'est encore pire car c'est loin d'être le meilleur aspect de
C++ !

Sur les forums d'échecs, la question du "meilleur langage" revient
souvent et les vertus/défauts du C++ y sont souvent débattus :
http://talkchess.com/forum/viewtopic.php?p11921#311921



J'aime bien cette phrase :
"If you program reasonably, there is no difference in speed between C
and C++...".
C'est le summum ;-)
je n'ai pas été plus loin.

http://talkchess.com/forum/viewtopic.php?p%7552#257552




<pseudo-troll>
Je pense que si ce sont les performances qui priment, il vaut mieux
programmer en assembleur ou en Forth.
Sur certains processeurs 8 bits comme le 6502 de l'Apple II, il y avait
de très bons programmes d'échec (je veux dire en performance, pour
l'époque).
</pseudo-troll>
Avatar
Wykaaa
Marc Espie a écrit :
In article <4b5fded2$0$928$,
Richard Delorme wrote:
Le 26/01/2010 19:35, Marc Espie a écrit :
Ca pue (au sens anti-pattern). Si ta classe est assez complexe pour
pouvoir tomber sur ce genre de choses, c'est generalement que tu essaies de
lui faire faire trop de choses, et qu'elle gagnerait grandement a etre
decoupee en morceaux plus petits, pour lesquels ce genre de souci ne se
poserait plus.


Pas nécessairement. Je prend un exemple, un coup dans un jeu d'échec.
Une implémentation simplifiée sous forme de classe pourrait être :

class Move {
// fonctions membres privées
public:
struct {
Coordinate x;
Piece piece;
} from, to;
Piece promotion;
int value;

// fonctions membres publiques.
}

Pourquoi initialiser la variable promotion si la pièce de départ n'est
pas un pion, où, même si c'est un pion, la case d'arrivée n'est pas sur
la dernière rangée ?
La valeur du coup, la variable value, est issue d'un long calcul. A quoi
bon y mettre une valeur bidon ?



Merci d'apporter de l'eau a mon moulin en donnant un exemple ou la
conception n'est clairement pas finie. Tu as un truc qui est Move + value,
ici, et qui devrait donc s'appuyer sur un class Move.

Ta definition de Move est bizarre, je comprend tres bien le Coordinate,
mais pourquoi piece de depart et piece d'arrivee ? tu modelises les
captures ?

Ou sont les roques dans tout ca ?

Rien que le fait d'avoir un attribut qui sera parfois defini, mais pas
toujours, ca tendrait a indiquer que tu devrais avoir une class abstraite
Move, avec plusieurs sous-classes possedant eventuellement des attributs
differents. Tu vas me dire, performance, mais je ne suis meme pas convaincu
avant d'avoir explicitement fait le test.



Encore une fois, je suis tout à fait d'accord avec toi.

J'aurais envie de repondre design semi-objet pas fini, avec encore une
grosse dose de procedural.



C'est l'effet de la programmation de "style C" en C++... et ça
correspond à ce que je dis dans un autre post de ce fil : programmer en
style C avec C++, c'est pire que de rester en C et on le voit avec éclat
ici. La classe Move est à revoir totalement et, je le répète,
"promotion" n'a rien à faire ici.

Les variables non initialisees (et leur copain, les switch sur un champ type)
sont des symptomes de design faits par des gens qui n'ont pas encore bien
integre la conception objet (ou qui, pour de basses questions de temps,
n'ont pas termine leur design).



En approche objet, je n'utilise jamais des enums. Je passe toujours par
l'héritage.
Un enum, c'est une classe abstraite et il y a autant de sous-classes que
de valeurs dans l'enum.
Avatar
Stan
On 27 jan, 20:45, Wykaaa wrote:

En approche objet, je n'utilise jamais des enums. Je passe toujours par
l'héritage.
Un enum, c'est une classe abstraite et il y a autant de sous-classes que
de valeurs dans l'enum.



Faut pas faire dans le dogmatisme.
Il faut utiliser les enums pour ce quoi elle sont utiles;
effectivement, si c'est pour faire un mécanisme de sélection
de type, le polymorphisme est plus adapté.
Mais dans ce cas, tu aurais en dire autant des switches.

J'ai vu beaucoup de projets où l'héritage était utilisé à outranc e,
où tout était modélisé en classes :
ces programmes étaient difficiles à comprendre et à maintenir.

--
-Stan
Avatar
James Kanze
On Jan 27, 8:17 am, Wykaaa wrote:
Richard Delorme a écrit :



> Le 26/01/2010 19:35, Marc Espie a écrit :
>> In article<4b5f22b7$0$17500$,
>> Richard Delorme wrote:
>>> La réalité peut être plus complexe. En pratique une classe peut -être
>>> assez compliquée et n'avoir besoin que d'une partie de ses variable s
>>> initialisées selon la situation. Tout initialiser dans le construct eur
>>> (ou pire, avoir un compilateur qui initialiserait tout par défaut) peut
>>> causer des problèmes de performances. L'idéal est de n'initialise r que
>>> ce qui est nécessaire avant son utilisation.

>> Ca pue (au sens anti-pattern). Si ta classe est assez complexe pour
>> pouvoir tomber sur ce genre de choses, c'est generalement que tu
>> essaies de
>> lui faire faire trop de choses, et qu'elle gagnerait grandement a etre
>> decoupee en morceaux plus petits, pour lesquels ce genre de souci ne s e
>> poserait plus.

Entièrement d'accord avec toi.





> Pas nécessairement. Je prend un exemple, un coup dans un jeu d'éche c.
> Une implémentation simplifiée sous forme de classe pourrait être :

> class Move {
> // fonctions membres privées
> public:
> struct {
> Coordinate x;
> Piece piece;
> } from, to;
> Piece promotion;
> int value;

> // fonctions membres publiques.
> }

> Pourquoi initialiser la variable promotion si la pièce de départ n' est
> pas un pion, où, même si c'est un pion, la case d'arrivée n'est p as sur
> la dernière rangée ?

Cette classe en fait déjà trop. Pourquoi mélanger le coup avec la
promotion ?

> La valeur du coup, la variable value, est issue d'un long calcul. A quo i
> bon y mettre une valeur bidon ?

Si, à l'initialisation d'une instance de classe, il y a des attributs
qu'on ne sait pas initialiser dans le constructeur, c'est qu'il y a un
défaut de conception. C'est le cas de ta classe Move car "promotion" ne
doit pas se trouver là.

> Pour moi, l'état indéterminée d'une variable a du sens et je ne
> comprends pas cette volonté de mettre une valeur déterminée à t out prix
> pour tout.

Non, il n'y a aucun sens à avoir des variables avec un état indéter miné.
C'est forcément le signe d'un défaut de conception quelque part.

> En pratique, cette classe ne contient ni constructeur ni destructeur.

C'est déjà mauvais signe.

> Les données du coup sont initialisées directement depuis son conten eur
> (un tableau de coups), car il est plus simple de générer l'ensemble des
> coups (ou tout du moins d'une famille de coups), qu'un coup isolé.

D'accord mais ce n'est pas parce que l'on va faire comme ça que la
classe qui décrit 1 coup ne doit pas avoir de constructeur pour
initialiser ses propres attributs.



> Peut-être cette façon de procéder est-elle un anti-pattern, mais c'est
> la manière idiomatique qu'utilise tous les programmes d'un niveau
> acceptable écrit en C++.

Ton exemple est totalement anti-pattern, effectivement.
Ce n'est pas parce que la plupart des programmes C++ sont mal écrits
(mettons au moins 90%) qu'il faut justifier cette manière de faire.

[couic valgrind : mais je suis d'accord avec Marc]


Avatar
James Kanze
On Jan 27, 3:26 pm, Richard Delorme wrote:
Le 27/01/2010 09:17, Wykaaa a écrit :
> Richard Delorme a écrit :
>> Le 26/01/2010 19:35, Marc Espie a écrit :
>>> In article<4b5f22b7$0$17500$,



[...]
>> Pas nécessairement. Je prend un exemple, un coup dans un jeu d'éch ec.
>> Une implémentation simplifiée sous forme de classe pourrait être :



>> class Move {
>> // fonctions membres privées
>> public:
>> struct {
>> Coordinate x;
>> Piece piece;
>> } from, to;
>> Piece promotion;
>> int value;



>> // fonctions membres publiques.
>> }
>> Pourquoi initialiser la variable promotion si la pièce de
>> départ n'est pas un pion, où, même si c'est un pion, la
>> case d'arrivée n'est pas sur la dernière rangée ?



> Cette classe en fait déjà trop. Pourquoi mélanger le coup avec la
> promotion ?



Parce que, conceptuellement, la promotion est un attribut du coup.



>> La valeur du coup, la variable value, est issue d'un long
>> calcul. A quoi bon y mettre une valeur bidon ?



> Si, à l'initialisation d'une instance de classe, il y a des
> attributs qu'on ne sait pas initialiser dans le
> constructeur, c'est qu'il y a un défaut de conception.



Pour "value" je fais comment? Pour moi la mauvaise réflexion
est de ce demander si je vais pouvoir initialiser (autrement
qu'avec une valeur bidon) une variable pour décider de la
rendre membre ou non. C'est ce focaliser sur un dogme qui ne
fait pas partie du langage mais juste une opinion sur ce
qu'est une hypothétique bonne conduite. Moi je préfère être
pragmatique. Mes coups, aux échecs, je les note. Cette note
est pour moi, indépendamment de tout langage de programmation
un attribut du coup. donc elle doit faire partie de la classe
Move.



> C'est le cas de ta classe Move car "promotion" ne
> doit pas se trouver là.



Ah et ou ça alors ?
En notation algébrique standard (SAN) on écrit p.ex., hxg1=Q.
Si je doit lire un tel coup, il faut bien que je stocke le =Q
quelque part ?



Maintenant si le coup est Qd4, la promotion
n'a pas de sens. Ma fonction pour lire de tel coup se présente
comme ça :
void Move::from_SAN(std::istream &is, const Board &board);
et à l'usage c'est juste un move.from_SAN(is, board); qu'il y
ait un coup avec ou sans promotion, m'importe peu. Si je met
la promotion ailleurs, je ne vois pas comment lire ce coup de
manière aussi simple.



C'est peut-être un Fallible<Promotion> qu'il te faut ?

>> Pour moi, l'état indéterminée d'une variable a du sens et
>> je ne comprends pas cette volonté de mettre une valeur
>> déterminée à tout prix pour tout.



> Non, il n'y a aucun sens à avoir des variables avec un état indét erminé.



Si, ça représente un état de connaissance partiel des membres
de la classe.



Mais il faut bien savoir si la valeur est présente ou non. Ce
qui implique soit une valeur hors-bande, soit quelque chose
comme Fallible. Or, la valeur hors-bande, il faut l'initialiser,
et Fallible, lui, a un constructeur qui l'initialise.

[...]
> Ton exemple est totalement anti-pattern, effectivement.



Je n'en suis pas sûr. Une conception inefficace en terme de
performance est un anti-pattern.



Dans certains contextes. Ce n'est pas une règle générale. (Dans
le contexte d'un jeu d'échecs, je conçois bien que la
performance ait de l'importance.)

--
James Kanze