Constantes modifiables en C++

Le
Pierre Maurette
Bonjour,
Il est fréquent que des variables (de tous types) soient initialisées
par la lecture d'un fichier INI par exemple, voire un calcul ou
l'appel d'une fonction en début de programme.
Il peut arriver que ces "constantes" soient modifiables
"exceptionnellement" par un utilisateur identifié (on peut alors se
ramener au précédent, par clôture/initialisation).
Il me semble normal de conserver le statut const à ces variables. Pour
l'instant, j'utilise quelques cast, et ça roule.

J'aimerais connaître la stratégie des uns et des autres face à ce
petit problème.
--
Merci,

Pierre
Vos réponses Page 1 / 2
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Falk Tannhäuser
Le #735672
Pierre Maurette wrote:

Bonjour,
Il est fréquent que des variables (de tous types) soient initialisées
par la lecture d'un fichier INI par exemple, voire un calcul ou
l'appel d'une fonction en début de programme.
Il peut arriver que ces "constantes" soient modifiables
"exceptionnellement" par un utilisateur identifié (on peut alors se
ramener au précédent, par clôture/initialisation).
Il me semble normal de conserver le statut const à ces variables. Pour
l'instant, j'utilise quelques cast, et ça roule.

J'aimerais connaître la stratégie des uns et des autres face à ce
petit problème.
Solution possible :

- Encapsuler ces variables dans une (des) classe(s) en les déclarant 'private' ;
- Modification uniquement par des fonctions membres de la classe (peut-être
uniquement le constructeur) ;
- Les accéder par des fonctions membres qualifiées 'const' et qui renvoient
les contenues de ces variables soit par valeur, soit par référence sur 'const'.

Le cas échéant, ces classes devraient être des singletons.

À +
Falk

Pierre Maurette
Le #735667
Falk Tannhäuser
Pierre Maurette wrote:

Bonjour,
Il est fréquent que des variables (de tous types) soient initialisées
par la lecture d'un fichier INI par exemple, voire un calcul ou
l'appel d'une fonction en début de programme.
Il peut arriver que ces "constantes" soient modifiables
"exceptionnellement" par un utilisateur identifié (on peut alors se
ramener au précédent, par clôture/initialisation).
Il me semble normal de conserver le statut const à ces variables. Pour
l'instant, j'utilise quelques cast, et ça roule.

J'aimerais connaître la stratégie des uns et des autres face à ce
petit problème.
Solution possible :

- Encapsuler ces variables dans une (des) classe(s) en les déclarant 'private' ;
- Modification uniquement par des fonctions membres de la classe (peut-être
uniquement le constructeur) ;
- Les accéder par des fonctions membres qualifiées 'const' et qui renvoient
les contenues de ces variables soit par valeur, soit par référence sur 'const'.

Le cas échéant, ces classes devraient être des singletons.
Merci.

En fait, je me mélangeais les neurones hors de toute situation réelle
de programation avec des cast de const.
Dans ma vrai vie, j'utilise C++Builder et un composant TDataModule en
appliquant votre solution.
--
Pierre


kanze
Le #721754
Pierre Maurette news:
Il est fréquent que des variables (de tous types) soient initialisées
par la lecture d'un fichier INI par exemple, voire un calcul ou
l'appel d'une fonction en début de programme. Il peut arriver que ces
"constantes" soient modifiables "exceptionnellement" par un
utilisateur identifié (on peut alors se ramener au précédent, par
clôture/initialisation). Il me semble normal de conserver le statut
const à ces variables. Pour l'instant, j'utilise quelques cast, et ça
roule.


Je suis curieux comment. Si j'écris :

extern int const i = 0 ;

et j'essaie plus tard à modifier la variable, au moyen de :

const_cast< int& >( i ) = 1 ;

j'ai un comportement indéfini, qui en fait ne marche pas toujours.

En ce qui concerne les variables initialisées à partir des fichiers de
configuration (.ini ou d'autres -- aussi depuis la registry sous
Windows), j'utilise une classe singleton qui contient la
configuration -- c-à-d que je lis le fichier une fois, et le maintient
dans un std::set (ou un tableau haché). Normalement, l'interface du
singleton ne donne pas d'accès en écriture aux éléments dans ce
tableau ; pour le modifier, il faut appeler une fonction spécial avec le
nom du fichier.

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Pierre Maurette
Le #721751
typa:

Pierre Maurette news:
Il est fréquent que des variables (de tous types) soient initialisées
par la lecture d'un fichier INI par exemple, voire un calcul ou
l'appel d'une fonction en début de programme. Il peut arriver que ces
"constantes" soient modifiables "exceptionnellement" par un
utilisateur identifié (on peut alors se ramener au précédent, par
clôture/initialisation). Il me semble normal de conserver le statut
const à ces variables. Pour l'instant, j'utilise quelques cast, et ça
roule.


Je suis curieux comment. Si j'écris :

extern int const i = 0 ;

et j'essaie plus tard à modifier la variable, au moyen de :

const_cast< int& >( i ) = 1 ;

j'ai un comportement indéfini, qui en fait ne marche pas toujours.
Je faisais parfois des trucs comme:

const int tt = 0;
*const_cast<int*>(&tt) = 20;
*(int*)(&tt) = 21;
Ça passe sans avertir sur mes compilos.
Peut-être "par hasard" ? ;-)
Mais peu importe, voir ma réponse au post de Falk.

En ce qui concerne les variables initialisées à partir des fichiers de
configuration (.ini ou d'autres -- aussi depuis la registry sous
Windows), j'utilise une classe singleton qui contient la
configuration -- c-à-d que je lis le fichier une fois, et le maintient
dans un std::set (ou un tableau haché). Normalement, l'interface du
singleton ne donne pas d'accès en écriture aux éléments dans ce
tableau ; pour le modifier, il faut appeler une fonction spécial avec le
nom du fichier.
Pour les INI, j'utilise la classe TIniFile (avec l'avantage d'avoir

une TRegistryIniFile, qui facilite le basculement d'un choix à
l'autre).

Pierre


Falk Tannhäuser
Le #721748
Pierre Maurette wrote:
Je faisais parfois des trucs comme:
const int tt = 0;
*const_cast<int*>(&tt) = 20;
*(int*)(&tt) = 21;
Ça passe sans avertir sur mes compilos.
Peut-être "par hasard" ? ;-)


const int tt = 0;
int main()
{
*const_cast<int*>(&tt) = 20;
// ou simplement
//const_cast<int&>(tt) = 21;
return 0;
}

chez moi, ça passe la compilation sans broncher (gcc 3.3.1 Cygwin
sous Windows 2000) - le const_cast est là pour dire au compilo
de la fermer !
Par contre, à l'exécution, ce programme m'affiche "Signal 11"
(sous Linux: "Memory fault") sans qu'il y ait un std::cout
ou printf dedans - magique non ?

À plus
Falk

Pierre Maurette
Le #721480
Falk Tannhäuser
Pierre Maurette wrote:
Je faisais parfois des trucs comme:
const int tt = 0;
*const_cast<int*>(&tt) = 20;
*(int*)(&tt) = 21;
Ça passe sans avertir sur mes compilos.
Peut-être "par hasard" ? ;-)


const int tt = 0;
int main()
{
*const_cast<int*>(&tt) = 20;
// ou simplement
//const_cast<int&>(tt) = 21;
return 0;
}

chez moi, ça passe la compilation sans broncher (gcc 3.3.1 Cygwin
sous Windows 2000) - le const_cast est là pour dire au compilo
de la fermer !
Par contre, à l'exécution, ce programme m'affiche "Signal 11"
(sous Linux: "Memory fault") sans qu'il y ait un std::cout
ou printf dedans - magique non ?
1 - Au temps pour moi, les seuls tests "réels" que j'ai fait sont en

C. Les casts à la C++ compilent, mais après, c'est la guerre.
2 - Justement, j'avais posté parce que les cast me gênaient. C'est une
grosse bêtise, il y a uns solution dans chacun des langages à base de
retour de pointeur (ou reference) const, ou de getters.

Ce qui se passe dans:
*const_cast<int*>(&tt) = 20;
ou
int*ptt = const_cast<int*>(&tt);
*ptt = 45;
C'est qu'en castant à la barbare, on finit par initialiser une
pointeur (non const), temporaire dans le premier cas, à l'adresse d'un
const int. Si cette adresse est dans un segment read-only, on est de
la baise. Exception ou même "rien" (semble être le cas sous XP).

Pierre


Michel Michaud
Le #721479
Dans news:, Pierre
Je faisais parfois des trucs comme:
const int tt = 0;
*const_cast<int*>(&tt) = 20;
*(int*)(&tt) = 21;
Ça passe sans avertir sur mes compilos.
Peut-être "par hasard" ? ;-)
Mais peu importe, voir ma réponse au post de Falk.


Pour être clair et précis : un const_cast qui enlève un
const n'est correct (i.e. pas « undefined ») seulement
si on sait que l'objet n'est pas const au départ.

--
Michel Michaud
http://www.gdzid.com
FAQ de fr.comp.lang.c++ :
http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/

Pierre Maurette
Le #721476
"Michel Michaud"
Dans news:, Pierre
Je faisais parfois des trucs comme:
const int tt = 0;
*const_cast<int*>(&tt) = 20;
*(int*)(&tt) = 21;
Ça passe sans avertir sur mes compilos.
Peut-être "par hasard" ? ;-)
Mais peu importe, voir ma réponse au post de Falk.


Pour être clair et précis : un const_cast qui enlève un
const n'est correct (i.e. pas « undefined ») seulement
si on sait que l'objet n'est pas const au départ.
Voila...

Par exemple, celui-là est correct, je ne l'avais pas posté, parce
qu'un peu gag:

int Nom_a_la_con_pour_ecrire = 123;
const int* P = &Nom_a_la_con_pour_ecrire;
#define Param (*P)
// bla bla
//Param = 5; // Refusé
std::cout << Param << std::endl;

On est certain que la variable existe dans une zone RW.

Pierre


kanze
Le #721208
Pierre Maurette news:
typa:

Pierre Maurette news:
Il est fréquent que des variables (de tous types) soient
initialisées par la lecture d'un fichier INI par exemple, voire un
calcul ou l'appel d'une fonction en début de programme. Il peut
arriver que ces "constantes" soient modifiables
"exceptionnellement" par un utilisateur identifié (on peut alors se
ramener au précédent, par clôture/initialisation). Il me semble
normal de conserver le statut const à ces variables. Pour
l'instant, j'utilise quelques cast, et ça roule.


Je suis curieux comment. Si j'écris :

extern int const i = 0 ;

et j'essaie plus tard à modifier la variable, au moyen de :

const_cast< int& >( i ) = 1 ;

j'ai un comportement indéfini, qui en fait ne marche pas toujours.


Je faisais parfois des trucs comme:
const int tt = 0;
*const_cast<int*>(&tt) = 20;
*(int*)(&tt) = 21;
Ça passe sans avertir sur mes compilos.
Peut-être "par hasard" ? ;-)


Tout à fait. Et il existe bien des cas et des implémentations où ça ne
marche pas -- ou bien, le compilateur voir que tt est const, et
l'utilise directement la valeur d'initialisation, plutôt que de lire la
variable, ou bien, le compilateur met la variable carrément dans un
segment protégé en écriture, qui donne un core à l'affectation.

Note bien que c'est parce que l'objet même est const. Quelque chose du
genre :

int maVar = 0 ;
int const& v = maVar ;

*const_cast< int* >( &maVar ) = 20 ;

est parfaitement légal.

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34



Jean-Marc Bourguet
Le #721206
Pierre Maurette
"Michel Michaud"
Dans news:, Pierre
Je faisais parfois des trucs comme:
const int tt = 0;
*const_cast<int*>(&tt) = 20;
*(int*)(&tt) = 21;
Ça passe sans avertir sur mes compilos.
Peut-être "par hasard" ? ;-)
Mais peu importe, voir ma réponse au post de Falk.


Pour être clair et précis : un const_cast qui enlève un
const n'est correct (i.e. pas « undefined ») seulement
si on sait que l'objet n'est pas const au départ.
Voila...

Par exemple, celui-là est correct, je ne l'avais pas posté, parce
qu'un peu gag:

int Nom_a_la_con_pour_ecrire = 123;
const int* P = &Nom_a_la_con_pour_ecrire;
#define Param (*P)
// bla bla
//Param = 5; // Refusé
std::cout << Param << std::endl;


Si tu veux jouer a ca, je prefere

int Nom_a_la_con_pour_ecrire = 123;
int& Nom_a_la_con_pour_lire = Nom_a_la_con_pour_ecrire;

(Mais bon, il y a toujours le probleme de l'ordre d'initialisation des
statiques).

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org



Publicité
Poster une réponse
Anonyme