This is my sample 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;
}
If I comment out #include <string>
I don't get any compiler error, I guess because it's kind of included through #include <iostream>
. If I "right-click --> Go to Definition" in Microsoft VS they both point to the same line in the xstring
file:
typedef basic_string<char, char_traits<char>, allocator<char> >
string;
But when I run my program, I get an exception error:
0x77846B6E (ntdll.dll) in OperatorString.exe: 0xC00000FD: Stack overflow (Parameter: 0x00000001, 0x01202FC4)
Any idea why I get a runtime error when commenting out #include <string>
? I'm using VS 2013 Express.
Indeed, very interesting behavior.
Any idea why I get I runtime error when commenting out
#include <string>
With MS VC++ compiler the error happens because if you do not #include <string>
you won't have operator<<
defined for std::string
.
When the compiler tries to compile ausgabe << f.getName();
it looks for an operator<<
defined for std::string
. Since it was not defined, the compiler looks for alternatives. There is an operator<<
defined for MyClass
and the compiler tries to use it, and to use it it has to convert std::string
to MyClass
and this is exactly what happens because MyClass
has a non-explicit constructor! So, the compiler ends up creating a new instance of your MyClass
and tries to stream it again to your output stream. This results in an endless recursion:
start:
operator<<(MyClass) ->
MyClass::MyClass(MyClass::getName()) ->
operator<<(MyClass) -> ... goto start;
To avoid the error you need to #include <string>
to make sure that there is an operator<<
defined for std::string
. Also you should make your MyClass
constructor explicit to avoid this kind of unexpected conversion.
Rule of wisdom: make constructors explicit if they take only one argument to avoid implicit conversion:
class MyClass
{
string figName;
public:
explicit MyClass(const string& s) // <<-- avoid implicit conversion
{
figName = s;
}
const string& getName() const
{
return figName;
}
};
It looks like operator<<
for std::string
gets defined only when <string>
is included (with the MS compiler) and for that reason everything compiles, however you get somewhat unexpected behavior as operator<<
is getting called recursively for MyClass
instead of calling operator<<
for std::string
.
Does that mean that through
#include <iostream>
string is only included partly?
No, string is fully included, otherwise you wouldn't be able to use it.