OVH Cloud OVH Cloud

Code expérimental

16 réponses
Avatar
plouf
bonjour,

J'ai fait quelques essais et j'ai eu des
résultats étranges. Je me demande donc si le code
suivant est correct (il est très court):


#include <sstream>
#include <string>
#include <iostream>

using namespace std;

class logger: public stringstream
{
public:

logger() {}

logger& operator()() { return(*this); }

~logger()
{
cout << this << " " << this->str();
cout << endl ;
}
};


int main()
{
logger() << "jjj " << " jjj " << 5 ; // j'ai des doutes ici

logger()() << "jjj " << " jjj " << 5 ; // et ici aussi

logger log;
log << "jjj " << " kkk " << 1 ;
return(0);
}


Résultat : Curieusement g++ me donne le résultat suivant
==========

G++/cygwin :
0x76ed40 0x436000 jjj 5 <== Voici ce que je ne comprends pas
0x76ed40 jjj jjj 5
0x76ed40 jjj kkk 1

VC++6 :
006BFCD4 jjj jjj 5
006BFC48 jjj jjj 5
006BFD60 jjj kkk 1

En plus, ni g++ ni vc++6 ne me mettent de warnings.
Ai-je fait un "Undefined Behaviour" quelque part ?
( Je pense surtout au deux premiers cas, mais le
destructeur semble être appelé suffisamment tard car,
sinon, il n'y aurait aucun affichage ).

6 réponses

1 2
Avatar
plouf79
On Fri, 21 Oct 2005 01:24:20 +0200, plouf :

~logger()
{
cout << this << " " << this->str();
cout << endl ;


Peux-tu garantir que ce code ne lance pas d'exception ?


Non pourquoi ? Qu'est-ce qui ne va pas ?


int main()
{
logger() << "jjj " << " jjj " << 5 ; // j'ai des doutes ici


Si je ne m'abuse, un temporaire est créé ; il existe pendant toute
l'exécution de l'expression (i.e. jusqu'au point-virgule). Mais je
n'en jurerais pas.
Je ne connaissais cette "régle". Merci beaucoup.



Avatar
Fabien LE LEZ
On 22 Oct 2005 13:52:27 -0700, :

~logger()
{
cout << this << " " << this->str();
cout << endl ;


Peux-tu garantir que ce code ne lance pas d'exception ?


Non pourquoi ? Qu'est-ce qui ne va pas ?


Cf le thread "Re: peut-on définir une fonction membre statique dans un
fichier .cpp ?"

Autant le dire tout de suite, ça n'a pas vraiment d'importance dans un
code expérimental.

Imagine le code suivant :

void f()
{
logger mon_logger;
throw 42;

}// Ici, le destructeur de mon_logger est appelé, alors qu'on est dans
le processus de lancement d'exception. Si jamais ce destructeur lance
lui aussi une exception, le programme se termine immédiatement.



Avatar
James Kanze
Fabien LE LEZ wrote:
On 22 Oct 2005 13:52:27 -0700, :


~logger()
{
cout << this << " " << this->str();
cout << endl ;





Peux-tu garantir que ce code ne lance pas d'exception ?




Non pourquoi ? Qu'est-ce qui ne va pas ?



Cf le thread "Re: peut-on définir une fonction membre statique
dans un fichier .cpp ?"


Autant le dire tout de suite, ça n'a pas vraiment d'importance
dans un code expérimental.


Imagine le code suivant :


void f()
{
logger mon_logger;
throw 42;


}// Ici, le destructeur de mon_logger est appelé, alors qu'on est dans
le processus de lancement d'exception. Si jamais ce destructeur lance
lui aussi une exception, le programme se termine immédiatement.


Si j'ai bien compris l'utilité de sa classe, elle ne doit servir
que comme temporaire. Du coup, le problème en est moindre.

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




Avatar
James Kanze
wrote:

plouf wrote:



[...]

logger()() << "jjj " << " jjj " << 5 ; // et ici aussi




Aucun problème : tu peux appeler une fonction membre, même non
const sur un objet temporaire. Et ton operator() renvoie un
lvalue non const ; il joue le rôle que jouait << "" autrefois.



Ce qui me posait problème ici c'est de renvoyer la référence
vers un objet temporaire. Je me demandait quand l'objet était
detruit et si ce que je faisais respectait bien la norme.


Mais comme l'objet reste "vivant" jusqu'a la fin de la ligne
c'est bon. J'avais pas du tout pensé au problème de surcharge
au début.


Pour être précis : pas jusqu'à la fin de la ligne, mais jusqu'à
la fin de l'expression complète.

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



Avatar
Fabien LE LEZ
On Sun, 23 Oct 2005 13:05:28 +0200, James Kanze :

Si j'ai bien compris l'utilité de sa classe, elle ne doit servir
que comme temporaire. Du coup, le problème en est moindre.


Peut-être. Mais si je ne m'abuse, le code suivant peut très bien
appeler terminate() :

logger()() << "jjj " << " jjj " << 5 ;

Ce qui, je te l'accorde, ne changerait pas grand-chose puisqu'il n'y a
de toutes façons aucun bloc try/catch dans son programme.

Avatar
James Kanze
Fabien LE LEZ wrote:
On Sun, 23 Oct 2005 13:05:28 +0200, James Kanze :


Si j'ai bien compris l'utilité de sa classe, elle ne doit
servir que comme temporaire. Du coup, le problème en est
moindre.



Peut-être. Mais si je ne m'abuse, le code suivant peut très
bien appeler terminate() :


logger()() << "jjj " << " jjj " << 5 ;


Seulement si je n'ai pas pris mes précautions vis-à-vis
bad_alloc (positionner new_handler, par exmple).

Il pourrait aussi donner un comportement indéfini, si par
exemple la pile déborde.

Sans prendre des précautions particulières, n'importe quel
programme C++ pourrait, en principe, échouer. Dans la pratique,
si la risque est assez grande pour la prendre en compte, dépend
de l'application.

Ce qui, je te l'accorde, ne changerait pas grand-chose
puisqu'il n'y a de toutes façons aucun bloc try/catch dans son
programme.


Il y a ça aussi:-).

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


1 2