Suppression d'instances inutiles ?

Le
Mickael Pointier
[Je viens de réinstaller mon PC suite à un changement d'OS, pourriez vous me
signaler le moindre problème dans ce message, que ca soit au niveau de
l'encodage ou que sais-je encore ? Merci d'avance.]

Je viens de passer de Visual 6 à VS.net 2003, et en convertissant mes
quelques projets C++, j'ai constaté un certain nombre de différences au
niveau du comportement de ces deux compilateurs. VS.net est visiblement bien
plus rigoureux et clair dans les erreurs qu'il signale, par contre il m'a
fait un truc que je n'ai pas trop aimé.

Ce que j'aimerai savoir si c'est lui qui a raison (la norme dit qu'il faut
le faire) et que donc je me reposait sur un comportement indéfini, ou bien
si ce que je faisait était pas mauvais en soit et que c'est donc VS.net qui
abuse.

Le point en question, c'est que dans ma librairie de déboggage, j'ai un
certain nombre de petites classes utilitaires qui n'ont de code que dans le
constructeur et dans le destructeur.

Certaines me servent à trouver des fuites de mémoire, d'autre à me sauver la
pile des appels dans un log, etc tout ca ne sert qu'en debug, en release
le code en question est supprimé.

Vu que c'était pratique, j'ai débordé de l'usage purement debug, et j'ai
commencé à m'en servir, comme par exemple avec ma microclasse de
manipulation de répertoires:

==
class tbDirectoryChanger
{
public:
tbDirectoryChanger(); //!< Simply store the current path
tbDirectoryChanger(const string &new_path); //!< Store the current path,
and set the new one
~tbDirectoryChanger(); //!< Restore the path stored during
construction
private:
void store_current_path(); //!< Utility function, store the current
path
string m_memo_path; //!< Contains the stored path
};
==

C'est pas forcément très beau, mais ca me permet dans un outil de build de
ressources qui gère beaucoup de chemins d'accès de faire des trucs dans le
genre:


{
tbDirectoryChanger tbDC("mon nouveau chemin de travail temporaire");
DoSomething(bla sur le nouveau chemin);
}


ce qui fait qu'à la sortie du scope, le directory est automatiquement
restauré.

Avec VC6 ca marchait bien, VC7 lui considère que la variable "tbDC" n'est
pas utilisée, et donc il vire l'instanciation de ma variable, ce qui fait
que mon répertoire n'est pas changé, et mon "DoSomething" il fait n'importe
quoi vu que le répertoire n'est pas validé.

Donc il a le droit de faire ca ???

La variable n'est pas utilisée, soit, mais le constructeur et le destructeur
ne sont pas triviaux.

Vala, merci de m'éclairer là dessus.

Mike
Vos réponses Page 1 / 6
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Jean-Marc Bourguet
Le #720009
"Mickael Pointier"
C'est pas forcément très beau, mais ca me permet dans un outil de build de
ressources qui gère beaucoup de chemins d'accès de faire des trucs dans le
genre:

...
{
tbDirectoryChanger tbDC("mon nouveau chemin de travail temporaire");
DoSomething(bla sur le nouveau chemin);
}
...

ce qui fait qu'à la sortie du scope, le directory est automatiquement
restauré.

Avec VC6 ca marchait bien, VC7 lui considère que la variable "tbDC" n'est
pas utilisée, et donc il vire l'instanciation de ma variable, ce qui fait
que mon répertoire n'est pas changé, et mon "DoSomething" il fait n'importe
quoi vu que le répertoire n'est pas validé.

Donc il a le droit de faire ca ???


A ma connaissance, non.

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

Régis Troadec
Le #720008
"Mickael Pointier" news:c5lob5$stc$

Salut,

[snip le reste]


============= > class tbDirectoryChanger
{
public:
tbDirectoryChanger(); //!< Simply store the current path
tbDirectoryChanger(const string &new_path); //!< Store the current
path,

and set the new one
~tbDirectoryChanger(); //!< Restore the path stored during
construction
private:
void store_current_path(); //!< Utility function, store the
current

path
string m_memo_path; //!< Contains the stored path
};
============= >
C'est pas forcément très beau, mais ca me permet dans un outil de build de
ressources qui gère beaucoup de chemins d'accès de faire des trucs dans
le

genre:

...
{
tbDirectoryChanger tbDC("mon nouveau chemin de travail temporaire");
DoSomething(bla sur le nouveau chemin);
}
...

ce qui fait qu'à la sortie du scope, le directory est automatiquement
restauré.

Avec VC6 ca marchait bien, VC7 lui considère que la variable "tbDC" n'est
pas utilisée, et donc il vire l'instanciation de ma variable, ce qui fait
que mon répertoire n'est pas changé, et mon "DoSomething" il fait
n'importe

quoi vu que le répertoire n'est pas validé.


Ca me parait tout a fait normal, à qui ou à quoi s'applique ta fonction
DoSomething ? Est-ce une fonction membre de tbDirectoryChanger, est-ce une
fonction statique ? Je ne le vois pas. Ta classe tbDirectoryChanger contient
une donnée membre string m_memo_path. Si DoSomething prend un string en
parametre, tu devrais avoir un accesseur pour passer le m_memo_path de ton
objet tbDC. Quelque chose du genre DoSomething(tbDEC.getPath()); par
exemple, avec std::string& getPath() const { return this->m_memo_path }


Donc il a le droit de faire ca ???


Par *virer ton instance*, que fait-il exactement, tbDC n'est pas contruit ?
Ca m'étonne. La question est de savoir ce que tu passes comme paramètre à
DoSomething.


La variable n'est pas utilisée, soit, mais le constructeur et le
destructeur

ne sont pas triviaux.

Vala, merci de m'éclairer là dessus.

Mike


Regis












Pierre Maurette
Le #719720
"Mickael Pointier"
[Je viens de réinstaller mon PC suite à un changement d'OS, pourriez vous me
signaler le moindre problème dans ce message, que ca soit au niveau de
l'encodage ou que sais-je encore ? Merci d'avance.]

Je viens de passer de Visual 6 à VS.net 2003, et en convertissant mes
quelques projets C++, j'ai constaté un certain nombre de différences au
niveau du comportement de ces deux compilateurs. VS.net est visiblement bien
plus rigoureux et clair dans les erreurs qu'il signale, par contre il m'a
fait un truc que je n'ai pas trop aimé.

Ce que j'aimerai savoir si c'est lui qui a raison (la norme dit qu'il faut
le faire) et que donc je me reposait sur un comportement indéfini, ou bien
si ce que je faisait était pas mauvais en soit et que c'est donc VS.net qui
abuse.

Le point en question, c'est que dans ma librairie de déboggage, j'ai un
certain nombre de petites classes utilitaires qui n'ont de code que dans le
constructeur et dans le destructeur.

Certaines me servent à trouver des fuites de mémoire, d'autre à me sauver la
pile des appels dans un log, etc... tout ca ne sert qu'en debug, en release
le code en question est supprimé.

Vu que c'était pratique, j'ai débordé de l'usage purement debug, et j'ai
commencé à m'en servir, comme par exemple avec ma microclasse de
manipulation de répertoires:

============= >class tbDirectoryChanger
{
public:
tbDirectoryChanger(); //!< Simply store the current path
tbDirectoryChanger(const string &new_path); //!< Store the current path,
and set the new one
~tbDirectoryChanger(); //!< Restore the path stored during
construction
private:
void store_current_path(); //!< Utility function, store the current
path
string m_memo_path; //!< Contains the stored path
};
============= >
C'est pas forcément très beau, mais ca me permet dans un outil de build de
ressources qui gère beaucoup de chemins d'accès de faire des trucs dans le
genre:

...
{
tbDirectoryChanger tbDC("mon nouveau chemin de travail temporaire");
DoSomething(bla sur le nouveau chemin);
}
...

ce qui fait qu'à la sortie du scope, le directory est automatiquement
restauré.

Avec VC6 ca marchait bien, VC7 lui considère que la variable "tbDC" n'est
pas utilisée, et donc il vire l'instanciation de ma variable, ce qui fait
que mon répertoire n'est pas changé, et mon "DoSomething" il fait n'importe
quoi vu que le répertoire n'est pas validé.

Donc il a le droit de faire ca ???

La variable n'est pas utilisée, soit, mais le constructeur et le destructeur
ne sont pas triviaux.

Vala, merci de m'éclairer là dessus.
J'avais remarqué que VC++7 avait l'optimisation virile et joyeuse.

Normal ou pas normal, je n'en sais pas assez en C++ et sur le
DoSomething pour me prononcer.
A tout hasard, essayez:
volatile tbDirectoryChanger tbDC("repert");
Pierre

Laurent Deniau
Le #719719
Pierre Maurette wrote:
"Mickael Pointier"

[Je viens de réinstaller mon PC suite à un changement d'OS, pourriez vous me
signaler le moindre problème dans ce message, que ca soit au niveau de
l'encodage ou que sais-je encore ? Merci d'avance.]

Je viens de passer de Visual 6 à VS.net 2003, et en convertissant mes
quelques projets C++, j'ai constaté un certain nombre de différences au
niveau du comportement de ces deux compilateurs. VS.net est visiblement bien
plus rigoureux et clair dans les erreurs qu'il signale, par contre il m'a
fait un truc que je n'ai pas trop aimé.

Ce que j'aimerai savoir si c'est lui qui a raison (la norme dit qu'il faut
le faire) et que donc je me reposait sur un comportement indéfini, ou bien
si ce que je faisait était pas mauvais en soit et que c'est donc VS.net qui
abuse.

Le point en question, c'est que dans ma librairie de déboggage, j'ai un
certain nombre de petites classes utilitaires qui n'ont de code que dans le
constructeur et dans le destructeur.

Certaines me servent à trouver des fuites de mémoire, d'autre à me sauver la
pile des appels dans un log, etc... tout ca ne sert qu'en debug, en release
le code en question est supprimé.

Vu que c'était pratique, j'ai débordé de l'usage purement debug, et j'ai
commencé à m'en servir, comme par exemple avec ma microclasse de
manipulation de répertoires:

============= >>class tbDirectoryChanger
{
public:
tbDirectoryChanger(); //!< Simply store the current path
tbDirectoryChanger(const string &new_path); //!< Store the current path,
and set the new one
~tbDirectoryChanger(); //!< Restore the path stored during
construction
private:
void store_current_path(); //!< Utility function, store the current
path
string m_memo_path; //!< Contains the stored path
};
============= >>
C'est pas forcément très beau, mais ca me permet dans un outil de build de
ressources qui gère beaucoup de chemins d'accès de faire des trucs dans le
genre:

...
{
tbDirectoryChanger tbDC("mon nouveau chemin de travail temporaire");
DoSomething(bla sur le nouveau chemin);
}
...

ce qui fait qu'à la sortie du scope, le directory est automatiquement
restauré.

Avec VC6 ca marchait bien, VC7 lui considère que la variable "tbDC" n'est
pas utilisée, et donc il vire l'instanciation de ma variable, ce qui fait
que mon répertoire n'est pas changé, et mon "DoSomething" il fait n'importe
quoi vu que le répertoire n'est pas validé.

Donc il a le droit de faire ca ???

La variable n'est pas utilisée, soit, mais le constructeur et le destructeur
ne sont pas triviaux.

Vala, merci de m'éclairer là dessus.


J'avais remarqué que VC++7 avait l'optimisation virile et joyeuse.
Normal ou pas normal, je n'en sais pas assez en C++ et sur le
DoSomething pour me prononcer.
A tout hasard, essayez:
volatile tbDirectoryChanger tbDC("repert");


Cela ne devrait rien changer.

Le constructeur non trivial et inconnu dans l'unite de compilation a le
droit d'avoir des effets de bords. Le compilateur doit donc construire
tbDC imperativement. La duree de vie de tbDC va jusqu'a la fin du bloc
courant donc au-dela de DoSomething. Je pencherais pour un bug mais ca
me parait enorme comme bug (difficile de croire qu'il n'ait pas ete
detecte par les ecrivains du compilateur). Peut-etre faudrait-il voir le
code du constructeur et de DoSomething pour en avoir le coeur net?

a+, ld.


Pierre Maurette
Le #719718
Laurent Deniau
Pierre Maurette wrote:
[...]

J'avais remarqué que VC++7 avait l'optimisation virile et joyeuse.
Normal ou pas normal, je n'en sais pas assez en C++ et sur le
DoSomething pour me prononcer.
A tout hasard, essayez:
volatile tbDirectoryChanger tbDC("repert");


Cela ne devrait rien changer.
Non, parce que ce n'est pas nécessaire, le problème est ailleurs.


C'est marrant, le volatile. Vous faites :
volatile int c = 12;
c=c;
c=c;
// rien d'autre pour c

il génère:
12 -> mémoire
mémoire -> registre
registre -> mémoire
mémoire -> registre
registre -> mémoire


Le constructeur non trivial et inconnu dans l'unite de compilation a le
droit d'avoir des effets de bords. Le compilateur doit donc construire
tbDC imperativement. La duree de vie de tbDC va jusqu'a la fin du bloc
courant donc au-dela de DoSomething. Je pencherais pour un bug mais ca
me parait enorme comme bug (difficile de croire qu'il n'ait pas ete
detecte par les ecrivains du compilateur). Peut-etre faudrait-il voir le
code du constructeur et de DoSomething pour en avoir le coeur net?


J'ai vérifié rapidement sans écrire les constructeurs ni destructeurs.
Le lieur me jette, mais c'est pas grave. Le constructeur est bien
appelé au moment de l'instanciation, et le destructeur à la fin de la
fonction. Avec VC++ 7.1 full, en release optimisée.
Doit y avoir du bug ailleurs.
Pour Mickael, vérifier en ajoutant l'option /FAs à la compilation, et
en regardant le fichier .asm (rechercher sur les mots du source, c'est
à la fin d'un gros fichier).

Pierre


kanze
Le #719717
"Mickael Pointier" news:
[...]
Le point en question, c'est que dans ma librairie de déboggage, j'ai
un certain nombre de petites classes utilitaires qui n'ont de code que
dans le constructeur et dans le destructeur.


Je me sers souvent des classes comme ça. Et non seulement pour des
motifs de mise au point ; c'est un idiome assez courant.

Certaines me servent à trouver des fuites de mémoire, d'autre à me
sauver la pile des appels dans un log, etc... tout ca ne sert qu'en
debug, en release le code en question est supprimé.


Je m'em sers pratiquement chaque fois que j'ai une ressource à gerer,
qui doit être impérativement libérée lorsque je pars, y compris si je
pars à cause d'une interruption.

Vu que c'était pratique, j'ai débordé de l'usage purement debug, et
j'ai commencé à m'en servir, comme par exemple avec ma microclasse de
manipulation de répertoires:

============= > class tbDirectoryChanger
{
public:
tbDirectoryChanger(); //!< Simply store the current path
tbDirectoryChanger(const string &new_path); //!< Store the current path,
and set the new one
~tbDirectoryChanger(); //!< Restore the path stored during
construction
private:
void store_current_path(); //!< Utility function, store the current
path
string m_memo_path; //!< Contains the stored path
};
=============
C'est pas forcément très beau, mais ca me permet dans un outil de
build de ressources qui gère beaucoup de chemins d'accès de faire des
trucs dans le genre:


C'est même l'idiome consacré en C++. Ça s'appelle RAII (Resource
Acquisition Is Initialization), pour des raisons historiques, mais on
s'en sert aujourd'hui pour beaucoup plus que seulement gerer des
ressources. Et si tu veux écrire du code « exception safe », il n'y a
que ça pour la gestion des ressources.

...
{
tbDirectoryChanger tbDC("mon nouveau chemin de travail temporaire");
DoSomething(bla sur le nouveau chemin);
}
...

ce qui fait qu'à la sortie du scope, le directory est automatiquement
restauré.


Tout à fait. Y compris si tu en sors suite à une interruption. C'est
tout l'intérêt de l'idiome.

Avec VC6 ca marchait bien, VC7 lui considère que la variable "tbDC"
n'est pas utilisée, et donc il vire l'instanciation de ma variable, ce
qui fait que mon répertoire n'est pas changé, et mon "DoSomething" il
fait n'importe quoi vu que le répertoire n'est pas validé.


J'ai dû mal à croire qu'il puisse avoir une erreur aussi grossière. Une
telle erreur rendrait le compilateur quasiment inutilisable avec du C++
moderne (Boost, etc.). Si c'était le cas, je crois qu'on en aurait
entendu parler déjà.

Donc il a le droit de faire ca ???


Certainement pas. Seulement si le constructeur et le destructeur sont
triviaux. C-à-d pas écrit par l'utilisateur.

La variable n'est pas utilisée, soit, mais le constructeur et le
destructeur ne sont pas triviaux.


La variable *est* utilisée. Ce n'est pas parce que tu ne la référence
pas une fois qu'elle est construite qu'elle ne sert pas.

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

Fabien LE LEZ
Le #719716
On Thu, 15 Apr 2004 12:33:32 +0200, "Mickael Pointier"

j'ai un
certain nombre de petites classes utilitaires qui n'ont de code que dans le
constructeur et dans le destructeur.


J'ai cru comprendre que ce genre de technique était également assez
courant dans wxWidget (anciennement wxWindows). Donc effectivement, si
VC++ vire ces objets avant l'heure, ça risque d'être sérieusement
problématique :-(


--
;-)
FLL, Epagneul Breton

Alexandre
Le #719713
============= > class tbDirectoryChanger
{
public:
tbDirectoryChanger(); //!< Simply store the current path
tbDirectoryChanger(const string &new_path); //!< Store the current
path,

and set the new one
~tbDirectoryChanger(); //!< Restore the path stored during
construction
private:
void store_current_path(); //!< Utility function, store the
current

path
string m_memo_path; //!< Contains the stored path
};
=============
on a pas le code des méthodes. Je fais donc un essai avec un corps

simplissime (mais non vide).

{
tbDirectoryChanger tbDC("mon nouveau chemin de travail temporaire");
DoSomething(bla sur le nouveau chemin);
}


Idem, on a pas le code (ni le proto) de DoSomething. Donc je fais un truc
simplissime pour tester.

Mon compilo C++ (borland C++ builder) passe tout sans pb (aucun warning) la
variable est bien construite puis détruite.
ça serait étrange que visual studio renferme un bug aussi gros. Un peu plus
de détails sur cette classe et DoSomething nous aiderait...

kanze
Le #719440
Pierre Maurette news:
J'avais remarqué que VC++7 avait l'optimisation virile et joyeuse.
Normal ou pas normal, je n'en sais pas assez en C++ et sur le
DoSomething pour me prononcer.
A tout hasard, essayez:
volatile tbDirectoryChanger tbDC("repert");


On programme à coups d'hazard, maintenant. Si le programme ne marche
pas, on modifie quelque chose de façon aléatoire, en espérant que par je
ne sais pas quelle miracle, il va se mettre à marcher.

J'espère ne jamais avoir à utiliser un programme que tu as écrit.

En fait, il doit bel et bien y avoir une erreur quelque part, et je
doute que ce soit le compilateur -- l'erreur serait trop grosse. Mais ça
doit être facile à mettre en évidence : il doit suffir d'activer les
traces qu'il a sûrement mis dans le constructeur et le destructeur, pour
voir bien si on y passe ou non.

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

kanze
Le #719439
Pierre Maurette news:
Laurent Deniau
Pierre Maurette wrote:
[...]


J'avais remarqué que VC++7 avait l'optimisation virile et joyeuse.
Normal ou pas normal, je n'en sais pas assez en C++ et sur le
DoSomething pour me prononcer.
A tout hasard, essayez:
volatile tbDirectoryChanger tbDC("repert");


Cela ne devrait rien changer.


Non, parce que ce n'est pas nécessaire, le problème est ailleurs.

C'est marrant, le volatile. Vous faites :
volatile int c = 12;
c=c;
c=c;
// rien d'autre pour c

il génère:
12 -> mémoire
mémoire -> registre
registre -> mémoire
mémoire -> registre
registre -> mémoire


Ce qui me semble tout à fait normal.

Sur une machine moderne, je m'attendrais aussi à ce que le compilateur
ajoute des barrières d'écriture et de lecture, de façon à s'assurer que
les l'écritures soient bien visibles de l'exterieur, et que les lectures
va réelement chercher au delà de la cache, mais la plupart des
compilateurs ne le font pas.

D'après tes commentaires, j'ai l'impression que vous ne connaissez pas
la signification de volatile. Ce qui n'est pas grave en soi -- un
programmeur d'applications n'en a jamais besoin. Mais dans ce cas-là, il
ne faut pas s'en servir n'en plus. Ni en conseiller l'utilisation à
d'autres.

Le constructeur non trivial et inconnu dans l'unite de compilation a
le droit d'avoir des effets de bords. Le compilateur doit donc
construire tbDC imperativement. La duree de vie de tbDC va jusqu'a la
fin du bloc courant donc au-dela de DoSomething. Je pencherais pour
un bug mais ca me parait enorme comme bug (difficile de croire qu'il
n'ait pas ete detecte par les ecrivains du compilateur). Peut-etre
faudrait-il voir le code du constructeur et de DoSomething pour en
avoir le coeur net?



Il faudrait bien en effet savoir exactement le contexte. Parce que je ne
peux pas croire que le compilateur ôte systèmatiquement de telles
variables. Comme j'ai écris par ailleurs, ça fait partie d'un idiome
consacré (RAII), décrit dans prèsque tous les textes C++.

J'ai vérifié rapidement sans écrire les constructeurs ni destructeurs.
Le lieur me jette, mais c'est pas grave. Le constructeur est bien
appelé au moment de l'instanciation, et le destructeur à la fin de la
fonction. Avec VC++ 7.1 full, en release optimisée. Doit y avoir du
bug ailleurs.

Pour Mickael, vérifier en ajoutant l'option /FAs à la compilation, et
en regardant le fichier .asm (rechercher sur les mots du source, c'est
à la fin d'un gros fichier).


Et quoi encore ?

S'il a un mechanisme de trace (fortement conseillé pour tout sauf les
programmes les plus petits), il n'a que l'activer. S'il n'en a pas, il
pourrait penser d'y en ajouter un. Et en attendant, des sorties vers
std::cerr permet d'avancer -- est-ce que le constructeur est réelement
appelé ? Sinon, est-ce qu'on passe par le code où la variable est
déclarée ; si oui, est-ce que l'essai de changer le répertoire a
réussi@? (A priori, s'il y a eu un échec lors de l'essai de changer le
répertoire, une erreur aurait dû être logguée. Sauf qu'il me semble que
Michael a dit une fois qu'il travaille sur des jeux. Un domain que je ne
connais pas, mais où les règles de programmation son bien différentes
que ce que je vois d'habitude. C'est donc peut-être normal ou acceptable
qu'il n'a pas loggué l'erreur -- qu'est-ce qu'on ferait avec un log d'un
programme de jeu ?)

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



Publicité
Poster une réponse
Anonyme