为什么#include <string>可以防止堆栈溢出错误?
这是我的示例代码:
#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中“右键单击 - >转到定义”,它们都指向xstring
文件中的同一行:
typedef basic_string<char, char_traits<char>, allocator<char> >
string;
但是当我运行我的程序时,出现异常错误:
OperatorString.exe中的0x77846B6E(ntdll.dll):0xC00000FD:堆栈溢出(参数:0x00000001,0x01202FC4)
任何想法为什么我在注释掉#include <string>
时出现运行时错误? 我正在使用VS 2013 Express。
的确,非常有趣的行为。
任何想法为什么我在注释掉#include <string>
时出现运行时错误
使用MS VC ++编译器时会发生错误,因为如果不包含#include <string>
,则不会为std::string
定义operator<<
。
当编译器试图编译ausgabe << f.getName();
它寻找一个为std::string
定义的operator<<
。 由于没有定义,编译器寻找替代品。 有一个operator<<
为MyClass
定义,并且编译器试图使用它,并且使用它必须将std::string
转换为MyClass
而这正是发生的原因,因为MyClass
具有非显式构造函数! 因此,编译器最终会创建一个MyClass
的新实例,并尝试将其再次传输到输出流。 这导致了无限的递归:
start:
operator<<(MyClass) ->
MyClass::MyClass(MyClass::getName()) ->
operator<<(MyClass) -> ... goto start;
为了避免这个错误,你需要#include <string>
来确保有一个operator<<
为std::string
定义。 你也应该明确你的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
调用operator<<
for std::string
。
这是否意味着通过#include <iostream>
字符串仅被部分包含?
不,字符串是完全包含的,否则你将无法使用它。
问题是您的代码正在进行无限递归。 std::string
( std::ostream& operator<<(std::ostream&, const std::string&)
)的流操作符在<string>
头文件中声明,尽管std::string
本身在其他头文件中声明(由<iostream>
和<string>
)。
当你不包含<string>
,编译器试图找到一种方法来编译ausgabe << f.getName();
。
碰巧你已经定义了MyClass
的流操作符和一个承认std::string
的构造函数,所以编译器使用它(通过隐式构造),创建递归调用。
如果你声明explicit
构造函数( explicit MyClass(const std::string& s)
那么你的代码将不能编译了,因为没有方法来调用与流运营商std::string
,你将被迫包含<string>
标题。
编辑
我的测试环境是VS 2010,从警告级别1( /W1
)开始,它会警告您有关此问题的信息:
警告C4717:'operator <<':在所有控制路径上递归,函数将导致运行时堆栈溢出
链接地址: http://www.djcxy.com/p/24569.html上一篇: Why is #include <string> preventing a stack overflow error here?