为什么 #include <string> 在这里防止堆栈溢出错误?
Why is #include <string> preventing a stack overflow error here?
这是我的示例代码:
#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;
}
如果我注释掉 #include <string>
,我不会收到任何编译器错误,我猜是因为它是通过 #include <iostream>
包含的。如果我在 Microsoft VS 中 "right-click --> Go to Definition" 它们都指向 xstring
文件中的同一行:
typedef basic_string<char, char_traits<char>, allocator<char> >
string;
但是当我运行我的程序时,我得到一个异常错误:
0x77846B6E (ntdll.dll) in OperatorString.exe: 0xC00000FD: Stack overflow (Parameter: 0x00000001, 0x01202FC4)
知道为什么在注释 #include <string>
时出现 运行 时间错误吗?我正在使用 VS 2013 Express。
的确,非常有趣的行为。
Any idea why I get I runtime error when commenting out #include <string>
使用 MS VC++ 编译器会发生错误,因为如果您不 #include <string>
您将不会为 std::string
.[=39= 定义 operator<<
]
当编译器尝试编译 ausgabe << f.getName();
时,它会查找为 std::string
定义的 operator<<
。由于未定义,编译器会寻找替代方案。为 MyClass
定义了一个 operator<<
,编译器尝试使用它,要使用它,它必须将 std::string
转换为 MyClass
,这正是发生的情况,因为 MyClass
有一个非显式构造函数!因此,编译器最终会创建一个 MyClass
的新实例,并尝试将其再次流式传输到您的输出流。这导致无限递归:
start:
operator<<(MyClass) ->
MyClass::MyClass(MyClass::getName()) ->
operator<<(MyClass) -> ... goto start;
为避免错误,您需要 #include <string>
以确保为 std::string
定义了 operator<<
。此外,您应该使 MyClass
构造函数显式化,以避免这种意外的转换。
智慧法则:如果构造函数只接受一个参数,则将其显式化以避免隐式转换:
class MyClass
{
string figName;
public:
explicit MyClass(const string& s) // <<-- avoid implicit conversion
{
figName = s;
}
const string& getName() const
{
return figName;
}
};
看起来 operator<<
for std::string
仅在包含 <string>
时才定义(使用 MS 编译器),因此所有内容都会编译,但是您会遇到一些意外的行为operator<<
正在为 MyClass
递归调用,而不是为 std::string
.
调用 operator<<
Does that mean that through #include <iostream>
string is only included partly?
不,字符串是完整包含的,否则你将无法使用它。
问题是您的代码正在进行无限递归。 std::string
(std::ostream& operator<<(std::ostream&, const std::string&)
) 的流运算符在 <string>
header 文件中声明,尽管 std::string
本身在其他 header 文件中声明(包括<iostream>
和 <string>
).
当您不包含 <string>
时,编译器会尝试找到编译 ausgabe << f.getName();
.
的方法
碰巧你已经为 MyClass
定义了一个流运算符和一个允许 std::string
的构造函数,所以编译器使用它(通过 implicit construction),创建一个递归打电话。
如果您声明 explicit
您的构造函数 (explicit MyClass(const std::string& s)
),那么您的代码将无法再编译,因为无法使用 std::string
调用流运算符,并且您将被迫包括 <string>
header.
编辑
我的测试环境是 VS 2010,从警告级别 1 (/W1
) 开始,它会警告您有关问题:
warning C4717: 'operator<<' : recursive on all control paths, function will cause runtime stack overflow
这是我的示例代码:
#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;
}
如果我注释掉 #include <string>
,我不会收到任何编译器错误,我猜是因为它是通过 #include <iostream>
包含的。如果我在 Microsoft VS 中 "right-click --> Go to Definition" 它们都指向 xstring
文件中的同一行:
typedef basic_string<char, char_traits<char>, allocator<char> >
string;
但是当我运行我的程序时,我得到一个异常错误:
0x77846B6E (ntdll.dll) in OperatorString.exe: 0xC00000FD: Stack overflow (Parameter: 0x00000001, 0x01202FC4)
知道为什么在注释 #include <string>
时出现 运行 时间错误吗?我正在使用 VS 2013 Express。
的确,非常有趣的行为。
Any idea why I get I runtime error when commenting out
#include <string>
使用 MS VC++ 编译器会发生错误,因为如果您不 #include <string>
您将不会为 std::string
.[=39= 定义 operator<<
]
当编译器尝试编译 ausgabe << f.getName();
时,它会查找为 std::string
定义的 operator<<
。由于未定义,编译器会寻找替代方案。为 MyClass
定义了一个 operator<<
,编译器尝试使用它,要使用它,它必须将 std::string
转换为 MyClass
,这正是发生的情况,因为 MyClass
有一个非显式构造函数!因此,编译器最终会创建一个 MyClass
的新实例,并尝试将其再次流式传输到您的输出流。这导致无限递归:
start:
operator<<(MyClass) ->
MyClass::MyClass(MyClass::getName()) ->
operator<<(MyClass) -> ... goto start;
为避免错误,您需要 #include <string>
以确保为 std::string
定义了 operator<<
。此外,您应该使 MyClass
构造函数显式化,以避免这种意外的转换。
智慧法则:如果构造函数只接受一个参数,则将其显式化以避免隐式转换:
class MyClass
{
string figName;
public:
explicit MyClass(const string& s) // <<-- avoid implicit conversion
{
figName = s;
}
const string& getName() const
{
return figName;
}
};
看起来 operator<<
for std::string
仅在包含 <string>
时才定义(使用 MS 编译器),因此所有内容都会编译,但是您会遇到一些意外的行为operator<<
正在为 MyClass
递归调用,而不是为 std::string
.
operator<<
Does that mean that through
#include <iostream>
string is only included partly?
不,字符串是完整包含的,否则你将无法使用它。
问题是您的代码正在进行无限递归。 std::string
(std::ostream& operator<<(std::ostream&, const std::string&)
) 的流运算符在 <string>
header 文件中声明,尽管 std::string
本身在其他 header 文件中声明(包括<iostream>
和 <string>
).
当您不包含 <string>
时,编译器会尝试找到编译 ausgabe << f.getName();
.
碰巧你已经为 MyClass
定义了一个流运算符和一个允许 std::string
的构造函数,所以编译器使用它(通过 implicit construction),创建一个递归打电话。
如果您声明 explicit
您的构造函数 (explicit MyClass(const std::string& s)
),那么您的代码将无法再编译,因为无法使用 std::string
调用流运算符,并且您将被迫包括 <string>
header.
编辑
我的测试环境是 VS 2010,从警告级别 1 (/W1
) 开始,它会警告您有关问题:
warning C4717: 'operator<<' : recursive on all control paths, function will cause runtime stack overflow