Dies ist mein Beispielcode:
#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;
}
Wenn ich #include <string>
auskommentiere, bekomme ich keinen Compilerfehler, denke ich, weil er irgendwie durch enthalten ist #include <iostream>
. Wenn ich in Microsoft VS mit der rechten Maustaste auf -> Zur Definition gehe, klicken beide auf dieselbe Zeile in der xstring
Datei:
typedef basic_string<char, char_traits<char>, allocator<char> >
string;
Aber wenn ich mein Programm starte, erhalte ich einen Ausnahmefehler:
0x77846B6E (ntdll.dll) in OperatorString.exe: 0xC00000FD: Stapelüberlauf (Parameter: 0x00000001, 0x01202FC4)
Irgendeine Idee, warum ich beim Auskommentieren einen Laufzeitfehler bekomme #include <string>
? Ich verwende VS 2013 Express.
c++
string
stack-overflow
explicit
in der Luft
quelle
quelle
#include<iostream>
und<string>
beide könnten einschließen<common/stringimpl.h>
....\main.cpp(23) : warning C4717: 'operator<<': recursive on all control paths, function will cause runtime stack overflow
beim Ausführen dieser Zeilecl /EHsc main.cpp /Fetest.exe
Antworten:
In der Tat sehr interessantes Verhalten.
Mit dem MS VC ++ - Compiler tritt der Fehler auf, denn wenn Sie dies nicht tun, haben
#include <string>
Sie keineoperator<<
Definition fürstd::string
.Wenn der Compiler versucht zu kompilieren
ausgabe << f.getName();
, sucht er nach einemoperator<<
definierten fürstd::string
. Da es nicht definiert wurde, sucht der Compiler nach Alternativen. Es gibt einoperator<<
definiertes fürMyClass
und der Compiler versucht, es zu verwenden, und um es zu verwenden, muss es konvertiert werdenstd::string
,MyClass
und genau das passiert, weilMyClass
es einen nicht expliziten Konstruktor hat! Der Compiler erstellt also eine neue Instanz von IhnenMyClass
und versucht, diese erneut in Ihren Ausgabestream zu streamen. Dies führt zu einer endlosen Rekursion:Um den Fehler zu vermeiden, müssen Sie
#include <string>
sicherstellen, dass einoperator<<
definiert für iststd::string
. Außerdem sollten Sie IhrenMyClass
Konstruktor explizit angeben, um diese Art der unerwarteten Konvertierung zu vermeiden. Weisheitsregel: Machen Sie Konstruktoren explizit, wenn sie nur ein Argument verwenden, um eine implizite Konvertierung zu vermeiden:Es sieht aus wie
operator<<
fürstd::string
nur definiert wird , wenn<string>
(mit dem MS - Compiler) enthalten ist und für , dass alles compiles Grund, aber Sie etwas unerwartetes Verhalten bekommen , wieoperator<<
rekursiv für immer genannt ,MyClass
anstatt Aufrufoperator<<
fürstd::string
.Nein, die Zeichenfolge ist vollständig enthalten, da Sie sie sonst nicht verwenden könnten.
quelle
std::string
ohne#include<string>
alles kann passieren, nicht nur auf einen Kompilierungszeitfehler beschränkt. Das Aufrufen der falschen Funktion oder des falschen Operators ist anscheinend eine andere Option.Das Problem ist, dass Ihr Code eine unendliche Rekursion ausführt. Der Streaming-Operator für
std::string
(std::ostream& operator<<(std::ostream&, const std::string&)
) wird in der<string>
Header-Datei deklariert , obwohl erstd::string
selbst in einer anderen Header-Datei deklariert ist (eingeschlossen in<iostream>
und<string>
).Wenn Sie nicht einschließen,
<string>
versucht der Compiler, einen Weg zum Kompilieren zu findenausgabe << f.getName();
.Es kommt vor, dass Sie sowohl einen Streaming-Operator für
MyClass
als auch einen Konstruktor definiert haben, der a zuläsststd::string
, sodass der Compiler ihn verwendet (durch implizite Konstruktion ) und einen rekursiven Aufruf erstellt.Wenn Sie
explicit
Ihren Konstruktor (explicit MyClass(const std::string& s)
) deklarieren, wird Ihr Code nicht mehr kompiliert, da es keine Möglichkeit gibt, den Streaming-Operator mit aufzurufenstd::string
, und Sie gezwungen sind, den<string>
Header einzuschließen.BEARBEITEN
Meine Testumgebung ist VS 2010 und ab Warnstufe 1 (
/W1
) werden Sie vor dem Problem gewarnt :quelle