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

Constantes modifiables en C++

20 réponses
Avatar
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

10 réponses

1 2
Avatar
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.

À +
Falk

Avatar
Pierre Maurette
Falk Tannhäuser typa:

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


Avatar
kanze
Pierre Maurette wrote in message
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

Avatar
Pierre Maurette
typa:

Pierre Maurette wrote in message
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


Avatar
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 ?

À plus
Falk

Avatar
Pierre Maurette
Falk Tannhäuser typa:

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


Avatar
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.

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

Avatar
Pierre Maurette
"Michel Michaud" typa:

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


Avatar
kanze
Pierre Maurette wrote in message
news:...
typa:

Pierre Maurette wrote in message
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



Avatar
Jean-Marc Bourguet
Pierre Maurette writes:

"Michel Michaud" typa:

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



1 2