2015-12-08 2 views
2

Je me demandais juste pourquoi ce code est incorrect? Il appelle constamment le constructeur Foo et provoque un débordement de pile après un certain temps. Pourquoi cette chaîne d'utilisation avec ostream provoque-t-elle stackoverflow?

#include <iostream> 

    using namespace std; 

    class Foo 
    { 
     std::string str; 
    public: 
     Foo(const string& s) : str(s) 
     { 
      cout << "Foo constructor" << endl; 
     } 
     friend ostream& operator<<(ostream& os,const Foo& foo); 
    }; 

    ostream& operator<<(ostream& os,const Foo& foo) 
    { 
     os << foo.str; 
     return os; 
    } 

    int main() 
    { 
     Foo foo{"Hello"}; 
     cout << foo;  
     cin.get(); 
    } 

Je sais, je sais qu'il est autorisé à écrire

cout << foo.str << endl;

ou os << foo.str.c_str();

mais je veux savoir pourquoi cette erreur se produit ..

+0

Cela semble bien. Le problème doit être ailleurs. – juanchopanza

+0

Peut-être que c'est un bug Visual C++? – ChaosDev

+0

Ou quelque chose d'étrange dans 'cin.get()', que vous devriez probablement supprimer. – juanchopanza

Répondre

3

Le programme utiliser std::string et son opérateur de sortie, mais ne pas inclure l'en-tête <string>: lorsque vous utilisez <string> vous devez inclure cet en-tête. Le fait que std::string semble être défini en incluant <iostream> est insuffisant. Il n'est pas non plus portable: une implémentation différente peut choisir de déclarer uniquement mais pas de std::string (une déclaration est cependant nécessaire, car certains membres IOStream utilisent le type std::string).

Si l'opérateur de sortie pour std::string ne se trouve pas, l'expression

out << foo.str 

est interprété comme comme

out << Foo(foo.str) 

comme il est un opérateur de sortie pour Foo. Bien sûr, cela aboutit à une récursion infinie.

+0

Donc l'iostream inclut une chaîne tout comme la déclaration directe et la conversion correcte en ostream existent dans l'en-tête ? – ChaosDev

+0

@ChaosDev: Je n'ai pas MSVC++ accessible donc je ne sais pas ce qu'ils font exactement. Il apparaît comme si l'inclusion de '' ne _define_ 'std :: string' (sinon vous ne seriez pas capable de créer un membre de ce type) mais ne fournit pas toutes les déclarations de l'en-tête' '. Notamment, il semble y compris '' ne fournit pas ** une déclaration de l'opérateur de sortie 'std :: string' tandis que' 'fournit cet opérateur. –