Why is #include <string> preventing a stack overflow error here?
The problem is that your code is doing an infinite recursion. The streaming operator for std::string
(std::ostream& operator<<(std::ostream&, const std::string&)
) is declared in <string>
header file, although std::string
itself is declared in other header file (included by both <iostream>
and <string>
).
When you don't include <string>
the compiler tries to find a way to compile ausgabe << f.getName();
.
It happens that you have defined both a streaming operator for MyClass
and a constructor that admits a std::string
, so the compiler uses it (through implicit construction), creating a recursive call.
If you declare explicit
your constructor (explicit MyClass(const std::string& s)
) then your code won't compile anymore, since there is no way to call the streaming operator with std::string
, and you'll be forced to include the <string>
header.
EDIT
My test environment is VS 2010, and starting at warning level 1 (/W1
) it warns you about the problem:
warning C4717: 'operator<<' : recursive on all control paths, function will cause runtime stack overflow
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.