Voici mon exemple de code:
#include <iostream>
#include <string>
using namespace std;
class MyClass
{
string figName;
public:
MyClass(const string& s)
{
figName = s;
}
const string& getName() const
{
return figName;
}
};
ostream& operator<<(ostream& ausgabe, const MyClass& f)
{
ausgabe << f.getName();
return ausgabe;
}
int main()
{
MyClass f1("Hello");
cout << f1;
return 0;
}
Si je commente, #include <string>
je n'obtiens aucune erreur de compilation, je suppose que c'est en quelque sorte inclus #include <iostream>
. Si je "clique avec le bouton droit -> Aller à la définition" dans Microsoft VS, ils pointent tous les deux vers la même ligne dans le xstring
fichier:
typedef basic_string<char, char_traits<char>, allocator<char> >
string;
Mais lorsque j'exécute mon programme, j'obtiens une erreur d'exception:
0x77846B6E (ntdll.dll) dans OperatorString.exe: 0xC00000FD: débordement de pile (paramètre: 0x00000001, 0x01202FC4)
Une idée de la raison pour laquelle j'obtiens une erreur d'exécution lors de la mise en commentaire #include <string>
? J'utilise VS 2013 Express.
c++
string
stack-overflow
explicit
aéroporté
la source
la source
#include<iostream>
et<string>
pourraient tous les deux inclure<common/stringimpl.h>
....\main.cpp(23) : warning C4717: 'operator<<': recursive on all control paths, function will cause runtime stack overflow
avec l'exécution de cette lignecl /EHsc main.cpp /Fetest.exe
Réponses:
En effet, comportement très intéressant.
Avec le compilateur MS VC ++, l'erreur se produit car si vous ne le faites pas,
#include <string>
vous n'aurez pasoperator<<
défini pourstd::string
.Lorsque le compilateur essaie de compiler,
ausgabe << f.getName();
il recherche unoperator<<
fichier défini pourstd::string
. Puisqu'il n'a pas été défini, le compilateur recherche des alternatives. Il y a unoperator<<
défini pourMyClass
et le compilateur essaie de l' utiliser, et de l' utiliser , il doit convertirstd::string
àMyClass
c'est exactement ce qui se passe parce queMyClass
a un constructeur non explicite! Ainsi, le compilateur finit par créer une nouvelle instance de votreMyClass
et essaie de la diffuser à nouveau dans votre flux de sortie. Cela se traduit par une récursion sans fin:Pour éviter l'erreur, vous devez vous
#include <string>
assurer qu'il existe unoperator<<
fichier pourstd::string
. Vous devez également rendre votreMyClass
constructeur explicite pour éviter ce type de conversion inattendue. Règle de sagesse: rendre les constructeurs explicites s'ils ne prennent qu'un seul argument pour éviter la conversion implicite:Cela ressemble à
operator<<
forstd::string
est défini uniquement lorsque<string>
est inclus (avec le compilateur MS) et pour cette raison, tout se compile, mais vous obtenez un comportement quelque peu inattendu car iloperator<<
est appelé récursivement pourMyClass
au lieu d'appeleroperator<<
pourstd::string
.Non, la chaîne est entièrement incluse, sinon vous ne pourrez pas l'utiliser.
la source
std::string
sans#include<string>
toutes sortes de choses peuvent se produire, sans se limiter à une erreur de compilation. L'appel de la mauvaise fonction ou de l'opérateur est apparemment une autre option.Le problème est que votre code effectue une récursion infinie. L'opérateur de streaming pour
std::string
(std::ostream& operator<<(std::ostream&, const std::string&)
) est déclaré dans le<string>
fichier d' en- tête, bien qu'il soitstd::string
lui-même déclaré dans un autre fichier d'en-tête (inclus à la fois par<iostream>
et<string>
).Lorsque vous n'incluez pas,
<string>
le compilateur essaie de trouver un moyen de compilerausgabe << f.getName();
.Il arrive que vous ayez défini à la fois un opérateur de streaming pour
MyClass
et un constructeur qui admet astd::string
, de sorte que le compilateur l'utilise (via une construction implicite ), créant un appel récursif.Si vous déclarez
explicit
votre constructeur (explicit MyClass(const std::string& s)
), votre code ne se compilera plus, car il n'y a aucun moyen d'appeler l'opérateur de streaming avecstd::string
, et vous serez obligé d'inclure l'en-<string>
tête.ÉDITER
Mon environnement de test est VS 2010, et à partir du niveau d'avertissement 1 (
/W1
), il vous avertit du problème:la source