61 votes

Boucle infinie dans le constructeur sans for ou while

J'ai fait un test ici, mais la sortie est une boucle sans fin, je ne sais pas pourquoi.

En fait, je fais un autre test, mais lorsque j'ai écrit ceci, je ne comprends pas comment la boucle s'est produite. La sortie "ABC" est répétée.

#include <map>
#include <string>
#include <iostream>

class test
{
public:
   std::map <int, int> _b;
   test();
   test (std::map<int, int> & im);
   ~test();
   };

test::test()
{
  std::cout<<"abc";
  _b.clear();
  _b[1]=1;
  test(_b);
}

test::test(std::map <int, int>& im)
{
   std::cout<<im[1];
}

test::~test() {};

int main ()
{
   test a;  
}

94voto

templatetypedef Points 129554

Le problème ici est que le compilateur interprète

test(_b);

Pas comme le code qui crée un objet temporaire de type test passage en paramètre _b mais comme une déclaration de variable pour une variable nommée _b de type test en utilisant le constructeur par défaut. Par conséquent, ce qui ressemble à un morceau de code qui crée un objet temporaire de type test en utilisant le second constructeur est au contraire en train de créer récursivement un nouvel objet de type test et en invoquant le constructeur une autre fois.

Pour résoudre ce problème, vous pouvez donner à la variable un nom explicite, comme

test t(_b);

Ceci ne peut être interprété que comme une variable de type test nommé t initialisé à l'aide du deuxième constructeur.

J'ai jamais J'ai déjà vu cela, et je programme en C++ depuis des années. Merci de m'avoir montré encore une fois le coin de la langue !

Pour une explication officielle : Selon la spécification ISO C++03, §6.8 :

Il existe une ambiguïté dans la grammaire impliquant les déclarations d'expression et les déclarations : Un énoncé d'expression avec une conversion de type explicite de style fonction (5.2.3) comme sous-expression la plus à gauche peut être indiscernable d'une déclaration où le premier déclarateur commence par un (. Dans ces cas, la déclaration est une déclaration.

(C'est moi qui souligne). En d'autres termes, chaque fois que le C++ pourrait interpréter une déclaration comme une expression (le cast temporaire d'objet) ou comme une déclaration (d'une variable), il choisira la déclaration. La spécification C++ donne explicitement

T(a) ;

En tant qu'exemple de déclaration, et non pas de moulage de a à quelque chose de type T .

C'est le C++ Parse la plus vexante - ce qui ressemble à une expression est plutôt interprété comme une déclaration. J'ai déjà vu le MVP, mais je ne l'ai jamais vu dans ce contexte.

J'espère que cela vous aidera !

0voto

Pradheep Points 1315

Le problème est qu'à partir du constructeur, vous appelez à nouveau le constructeur test(_b).

test::test(){std::cout<<"abc";_b.clear();_b[1]=1;test(_b);}

voici ce qui se passe

chaque fois que vous appelez test(_b), il appelle d'abord le constructeur par défaut test::test et il appelle à son tour le test(_b) et la boucle continue jusqu'à ce que la pile déborde.

supprimer le test(_b) du constructeur par défaut

0voto

OlivierD Points 137

Je ne suis pas familier avec les particularités de la norme, mais il se peut que l'appel d'un constructeur dans un constructeur ne soit pas défini. En tant que tel, cela pourrait dépendre du compilateur. Dans ce cas particulier, cela provoque une récursion infinie de votre constructeur par défaut sans jamais appeler votre constructeur avec l'argument map.

La FAQ C++ 10.3 contient un exemple avec un constructeur qui a deux paramètres. Si vous ajoutez un paramètre int à votre second constructeur, tel que test(map, int) il présente un comportement plutôt normal.

Pour une bonne forme, je changerais simplement test::test(std::map <int, int>& im) pour test::testInit(std::map <int, int>& im) y test(_b) a testInit(_b) .

0voto

D.Shawley Points 30324

Je suis presque sûr que vous n'êtes pas réellement "appeler le constructeur" puisqu'ils ne sont pas directement appelables IIRC. Le jargon juridique avait à voir avec le fait que les constructeurs ne sont pas fonctions nommées - Je n'ai pas d'exemplaire de la norme sous la main, sinon je pourrais la citer. Je crois que ce que vous faites avec test(_b) crée une personne anonyme un temporaire qui invoque à nouveau le constructeur par défaut.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X