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

Suppression d'instances inutiles ?

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

10 réponses

1 2 3 4 5
Avatar
Fabien LE LEZ
On 16 Apr 2004 00:38:00 -0700, wrote:

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.


C'est une méthode parfois efficace quand on cherche une erreur
difficile à trouver : o
--
;-)
FLL, Epagneul Breton

Avatar
Régis Troadec
"Twxs" a écrit dans le message de
news:407fb2ec$0$15688$
Régis Troadec wrote:
"Mickael Pointier" a écrit dans le message de
news:c5lob5$stc$




Salut,


[snip le reste]



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.


tu n'as pas tout saisi, le DoSomething n'a rien a voire avec la classe
tbDirectoryChanger, elle indique juste une chose a faire dans le nouveau
repertoire courant


Il s'agissait d'obtenir des infos sur DoSomething. Je n'ai jamais dit que
DoSomething avait quelquechose à voir avec la classe. Et après tout,
l'idiome RAII n'est pas si strict et DoSomething aurait très bien pu être
une fonction membre. Par contre, Mickael ne possedait pas d'accesseur sur sa
ressource dans sa classe tbDirectoryChanger, pourtant nécessaire pour le
RAII. De toute façon, je crois qu'il a trouvé son erreur.


sinon, j'utilise frequement ce genre de technique et n'ai aucun probleme
sous tous les VC (6, 7.0 et 7.1). Bienqu'il me semble qu'une option de
compilation retire le code non utilisé, verifie qu'elle ne soit pas
activée.


Il y a bien des options d'optimisation comme /Oa et /Og qui vont permettre
*d'economiser* des variables et des instructions avec VC 6, mais je suis sûr
qu'il n'y a pas de telle option avec VC 6, pour les autres version je n'en
sais rien, mais ca m'étonnerait fort. Construire un objet, c'est quand même
différent d'une simple variable locale de type fondamental non référencée.

Regis

Twxs



Avatar
Loïc Joly
Mickael Pointier wrote:

warning C4930: 'tbDirectoryChanger tbDC(void)': prototyped function
not called (was a variable definition intended?)

En quoi cette écriture est-elle fausse ? Ca ne revient pas à dire
"utilise le constructeur non paramétré" ? Si quelqu'un pouvait
m'éclairer sur le problème, ca serait cool


La forme qui ne fonctionne pas est une declaration de fonction nommee
tbDC sans parametre et retournant un tbDirectoryChanger. Le warning
t'indique que tu declares cette fonction sans jamais l'appeler.



Donc en fait c'est Visual 6 qui ne fait pas les choses correctement.



J'ai déjà eu cette surprise avec VC++ 6.0 il y a un certain temps, donc
si, la version 6.0 considèrait déjà ça comme une déclaration de fonction.



Il faut se souvenir de deux choses:
- quand qqch est interpretable comme declaration de fonction et
definition, c'est la declaration qui prime;
- on peut declarer des fonctions localement.



Hu ? Je ne savais pas ca.


Il y a pire...

deque<string> coll3( istream_iterator<string>( cin ),
istream_iterator<string>() );

(voir le gotw 75 pour les détails)

--
Loïc



Avatar
kanze
Fabien LE LEZ wrote in message
news:...

On 16 Apr 2004 00:38:00 -0700, wrote:

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.


C'est une méthode parfois efficace quand on cherche une erreur
difficile à trouver : o


Tu as déjà vu un seul cas où des changements aléatoires ont donné un
programme correct. Moi non. Si on a un programme qui ne marche pas, on
commence par comprendre, puis on fait des modifications en fonction de
ce qu'on a compris.

--
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
kanze
"Mickael Pointier" wrote in message
news:<c5oil5$b6v$...

warning C4930: 'tbDirectoryChanger tbDC(void)': prototyped function
not called (was a variable definition intended?)

En quoi cette écriture est-elle fausse ? Ca ne revient pas à dire
"utilise le constructeur non paramétré" ? Si quelqu'un pouvait
m'éclairer sur le problème, ca serait cool


La forme qui ne fonctionne pas est une declaration de fonction
nommee tbDC sans parametre et retournant un tbDirectoryChanger. Le
warning t'indique que tu declares cette fonction sans jamais
l'appeler.


Donc en fait c'est Visual 6 qui ne fait pas les choses correctement.


Au contraire.

tbDirectoryChanger tbDC() ;

déclare une fonction extern, et VC l'a traité comme une declaration
d'une fonction externe. En plus, il en a donné un avertissement, ce qui
est bien.

Il faut se souvenir de deux choses:
- quand qqch est interpretable comme declaration de fonction et
definition, c'est la declaration qui prime;
- on peut declarer des fonctions localement.


Hu ? Je ne savais pas ca.
Quel est l'intérêt de déclarer une fonction locale ???


Ne pas casser du C ancien qui s'en sert:-).

Sérieusement, c'est bien pour des raisons histér^H^Horiques. C'est un
style qui n'est pas bien vu aujourd'hui, et qui n'est pas très répandu.
Mais c'était légal dans les premières versions de C, et jusqu'ici,
personne n'a trouvé que ça valait la peine de le changer.

--
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
kanze
"Mickael Pointier" wrote in message
news:<c5oam7$7q3$...
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++.


Depuis mon autre message où j'ai indiqué que le problème ne se
produisait que si j'utilisais la forme avec parenthèse,


tbDirectoryChanger tbDC ; // Définit une variable...
tbDirectoryChanger tbDC() ; // Déclare une fonction,
// implicitement extern...

C'est un peu bizarre, mais il y a des raisons historiques...

Quand tu déclares une fonction externe, c'est normal qu'il n'y a pas
d'appel d'un constructeur.

j'ai voulu voir si le compilateur générait un code différent dans le
cas où j'utilise new:

Que je fasses ca:
tbDirectoryChanger *ptr_tbdc=new tbDirectoryChanger;

ou ca:
tbDirectoryChanger *ptr_tbdc=new tbDirectoryChanger();


C'est parce que dans ce contexte-ci, la déclaration d'une fonction n'est
pas légale.

[...]
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 ?)


Dans un outil, et tout est bien loggé, c'est comme ca que je me suis
rendu compte du problème. L'outil exécute des scripts, et chaque fois
que je fais une grosse modification je lance mes scripts de test, et
là ca à foiré.

Mais bon, y'a log et log.


Tout-à-fait. Je travaille sur des serveurs qui n'ont pas droit de
s'arrêter. Quand il y a une anomalie de fonctionnement, on reconfigure
le trace, lui dire de prendre la nouvelle configuration en compte, et on
analyse le trace, le tout sans l'arrêter. Et selon la configuration, on
a des traces souvent jusqu'au niveau de chaque appel de fonction -- on
pourrait donc voir si le constructeur avait été appelé ou non.

Mais le but de ma question, c'était bien plutôt à démander si tu avais
écarté la possibilité que ce soit la commande de changement de
répertoire qui n'avait pas marché. C'est triste à dire, mais il y a
beaucoup de programmeurs qui oublient des petits détails comme vérifier
les codes de rétour des requêtes système. Dans le domaine où je
travaille, ça serait une faute grave, mais d'autres programmeurs peuvent
avoir d'autres exigeances.

Il me semble normal de détecter qu'une opération de changement de
répertoire échoue.


Il me semble normal à moi aussi. Mais j'ai tellement l'habitude qu'on me
dit que ce que je trouve normal ne l'est pas.

Par contre détecter le fait que le compilateur à décidé de ne pas
appeller le code en question, heu, je sais pas faire, si ce n'est en
le déduisant du fait que le code derrière foire lamentablement.


S'il y avait une trace dans le constructeur, tu aurait bien vu qu'il n'a
pas été appelé. Ou qu'il a été appelé, mais qu'il n'a pas fait ce qu'il
fallait (pour on ne sait pas quelle raison). Mais en fait, d'après ton
autre posting, je vois que le seul problème, c'est que tu t'attendais à
ce que le C++ soit un peu logique et orthogonal. Or, comme tout langage
qui n'est pas né hier, il a une histoire, qui fait que les choses ne
sont pas toujours aussi propre qu'on aimerait.

--
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
kanze
Pierre Maurette wrote in message
news:...
typa:

Pierre Maurette wrote in message
[...]

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.


Mais pas à g++ 3.2 (mingw, sous Windows). Il se contente de:
12 -> mémoire


Ce qui est contraire à la norme. Tu as écrit des instructions de lire
une valeur de la mémoire, et de l'écrire dans la mémoire. Le
comportement de la machine abstraite donc lit et écrit. Et quand une
variable est déclarée volatile, le compilateur est censé respecter le
comportement de la machine abstraite -- il y a du « défini par
l'implémentation », mais il ne concerne que ce que signifie un accès,
non si les accès ont lieu ou non.

Ceci dit, je ne constate ce comportement sous Sparc qu'avec des
variables auto. Dès que la variable est statique, ou que je passe par un
pointeur, g++ génère tous les accès qu'il faut. Or, puisque par
définition, une variable auto n'est visible nulle part ailleurs, on
pourrait arguer qu'un programme ne pourrait jamais faire la différence.
Personnellement, si on va traiter les variables volatile auto d'une
façon différentes des autres volatile, j'aurais préféré un
avertissement, du genre « volatile ne peut avoir aucune sémantique utile
sur une variable auto ».

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


Je vois que vous hésitez entre le tu et le vous. Je vous autorise l'un
et l'autre.


En général, dans les forums, on se tutoies, et je n'hésite pas. En fait,
j'avais écrit le vous avec l'intention d'inclure les autres participants
de ce sous-thread aussi. Être étonné que le compilateur n'optimise pas
quand il y a « volatile » me semble indiquer qu'on ne connaît pas sa
signification.

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.


L'amabilité est une seconde nature chez vous.

Je vais plus facilement vers le hard et l'assembleur que vers le C++
(grosses lacunes en C++, je me soigne), et le volatile est ma passion.


Passion ou non, il ne faut pas le conseiller « au hazard », dans les cas
où il ne peut pas avoir quoique ce soit à faire dans affaire.

Je suis l'ornithologue de l'informatique, le fou de la plume et du
croupion. Je fais beaucoup de tests et je trouve qu'utiliser volatile
pour forcer à la génération de code est facile. Il faut simplement se
méfier des compilateurs qui le gèrent mal.


Le mot clé volatile a été introduit dans le langage avec des buts
précis. C'est vrai qu'aujourd'hui, certains compilateurs le gèrent mal,
au point de le rendre complètement inutile, mais ce n'est réelement le
cas que sur des architectures avancées, où le fait d'émettre les
instructions machine de lecture ou d'écriture ne suffit pas pour qu'une
lecture ou une écriture ait réelement lieu sur le bus extern.

L'utilisation de volatile ou non ne peut pas changer la sémantique d'un
programme purement C++, où il n'y a rien d'autre qui ne vient lire ou
écrire dans la mémoire (ou dans ce qui se trouve aux adresses affectées
à la mémoire). Le mot clé volatile n'entre en jeu que quand on interface
avec des choses en dehors du langage -- son utilisation « type » est
pour des entrées/sorties mappées mémoires, ou pour l'interface entre les
procédures d'interruption et le niveau « normal » du code. Son rôle est
d'assurer que les modifications des uns soient visibles des autres.

Et si je ne vois pas comme ça un cas où j'écrirai « c = c ; » trois fois
de suite, il m'est bien arrivé d'écrire :

*pInterface = 0 ;
*pInterface = 0 ;
*pInterface = 0 ;

Trois fois de suite, et il fallait absolument qu'il y a eu trois
écritures pour que le chip adressé par pInterface soit correctement
initialisé. Alors, le type de pInterface, c'était bien unsigned char
volatile* ; sans la volatile, pas de garantie des trois écritures.

Il y a trop de sources qui présentent "à moitié" volatile, en se
contentant de parler de modifications possibles en dehors de l'emprise
du programme. Les normes citent ces cas, mais comme un exemple. Je me
demande s'il ne serait pas plus simple d'écrire que toute opération du
code source concernant un objet volatile doit être réellement codée,
dans le meilleur respect possible de la chronologie du source.


C'est à peu près l'intention. Mais évidemment, dans la mésure que le
code en question n'accède pas à quelque chose qui est visible de
l'extérieur, on ne peut pas le voir.

[...]

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 ?


J'aime bien voir le code généré, c'est mon vice, avec les volatiles.
Chacun ses danseuses. Le fichier .asm (ou le debogueur machine) est
une bonne solution, même s'il en existe d'autre, qui garantit la
conformité du code observé et du code définitif.


Il y a deux choses distinctes. Que tu aimes bien voir le générer, c'est
ton affaire. Comme tu dis, chacun son truc. En tant qu'ancien du
hardware, ça m'intrigue aussi un peu. Mais ce n'est pas en régardant le
généré qu'il va trouver le plus rapidement la solution à son problème.
En général, ce n'est pas une bonne technique de déboggage.

Je regrette que tu t'es senti un peu aggressé par mon posting, mais
j'avoue que s'il y a une chose que je supporte mal, c'est l'idée qu'on
peut débogguer un programme au coup d'« au hazard ». Si tu avais dit
qu'il fallait ajouter un volatile, parce que blah, blah, blah, avec des
raisons, et non simplement « au hazard », j'aurais répondu d'une façon
bien moins agressive. Même si les raisons n'étaient pas bonnes, il
arrive à tout le monde de se tromper, et j'aurais essayé à expliquer
pourquoi je les trouvais pas bonnes, d'une façon aimable et polie. Mais
« au hazard » ? Pourquoi pas insister que le nom du type commence par
un « C », « au hazard » ? Ou déclarer une variable bidon de type int
avant, « au hazard » ?

--
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
kanze
Pierre Maurette wrote in message
news:...
typa:

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


Cool, Raoul.
<OP>
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é.
</OP>
Mode affirmatif, donc je suppose que l'OP a pris les moyens de
vérifier que sa classe n'avait pas été instanciée.


Et moi, je ne suppose rien. Sinon que ni VC++ 6.0 ni VC++ 7.0 supprime
des variables comme ça, histoire de s'amuser. Je connais un peu Mickael
de ses postings dans la passée ; il n'est pas un débuttant, mais les
auteurs de VC++ 7.0 non plus. Si j'avais du code qui ne marche pas avec
VC++ 7.0, je supposerais d'abord mon code, et non le compilateur.

J'ai de gros doutes, je ne vois pas le compilateur zapper du code de
constructeur et destructeur. Mais par politesse (eh oui) je mets sur
le même plan mes doutes sur VC++ et sur son DoSomething.


C'est de la fausse politesse. Mickael a un problème. Pour avancer vers
une solution, il faut savoir exactement quel est son problème, la
probabilité que le compilateur ait supprimé une variable étant quasiment
nille dans ce cas-ci. Pour avancer, il faut savoir exactement ce qu'il a
fait comme tests, qui lui a donné l'impression que la variable a été
supprimée. Personne n'est parfaite, et je le trouve tout à fait normal
de démander des précisions d'informations.

C'est une figure de réthorique qui permet de ne pas passer pour un
goujat.

Je connais un peu le comportement (radical) de VC++7.1 face à
volatile. Saisir 9 caractères pour lever un doute, ce n'est pas cher.


La doute sur quoi ? Supposons que le programme aurait semblé marcher
avec volatile. Il n'est toujours pas correct. On ne sait pas pourquoi il
n'a pas marché avant. On ne sait pas ce qu'on a réelement changé. On ne
sait pas pourquoi il a l'air de marcher maintenant.

En somme, on n'est avancé en rien.

De plus, j'avoue que le C++ me réserve encore bien des surprises (et
pour longtemps encore:-() et je voulais vérifier. Votre message
précédent m'aurait totallement rassuré, mais il est arrivé un peu
tard.

Dans un second message que vous semblez ignorer, je signale que j'ai
testé sur le compilateur utilisé par l'OP et que la classe s'instancie
normalement :


Je ne l'avais pas testé, parce que je n'ai pas accès à ce compilateur.
Mais j'en étais assez sûr sans tester qu'il ne supprimait pas des
variables comme ça, sans raison. Qu'il devait y avoir donc quelque chose
d'autre, et que Mickael s'était trompé ou bien dans sa présentation, ou
bien dans son diagnose.

Mais mes commentaires restent : pourquoi ajouter volatile ? Qu'est-ce
que c'est censé de changer ? Et surtout : les changements du code « au
hazard » ne mènent jamais à du bien.

c'est LA réponse à LA question posée :

<OP>
Donc il a le droit de faire ca ???
</OP>
Il ne fait pas ça (VC++ .NET 2003). J'en profite pour donner une
méthode parmi d'autre pour lever tout doute sur le contenu de la
"release". La tentation est grande de se contenter de se mettre en
configuration "debug" et de tracer.


Je n'aime pas trop le debuggueur, mais je trouve que ça aurait été plus
utile que volatile. En fait, ajouter volatile n'aurait rien changé. Et
alors, en quoi serait-il plus avancé ?

--
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
Mickael Pointier
Donc en fait c'est Visual 6 qui ne fait pas les choses correctement.


Au contraire.

tbDirectoryChanger tbDC() ;

déclare une fonction extern, et VC l'a traité comme une declaration
d'une fonction externe. En plus, il en a donné un avertissement, ce
qui est bien.


Nope.
C'est VC7 qui a fait ce diagnostic.
VC6 ne signale rien, et m'a bien instancié ma variable.
[Ce qui est étrange vu que loic à eu le même comportement avec VC6...]


Bon, en tout cas j'aurais encore apris un truc sur le C++ (et le C par la
même occasion).

Franchement, c'est le genre d'héritage du C dont je me passerais bien :(

Merci tout le monde.

Mike


Avatar
Fabien LE LEZ
On 19 Apr 2004 01:21:25 -0700, wrote:

Si on a un programme qui ne marche pas, on
commence par comprendre


Justement, faire des modifications "au hasard" aide (parfois) à
comprendre. Bien sûr, il ne s'agit pas de laisser ces tests dans le
programme final, mais juste voir comment le bug réagit à des petites
modifications. En d'autres termes, jouer un peu avec le programme pour
tenter d'isoler le bug.
En fait, je m'aperçois que ce genre de manipulations m'apporte un
regard nouveau sur mon code, et me permet souvent de repérer des
erreurs.

--
;-)
FLL, Epagneul Breton

1 2 3 4 5