air*_*rne 121 c++ stack-overflow string explicit
这是我的示例代码:
#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.
Pav*_*l P 161
确实,非常有趣的行为.
知道为什么我在评论时出现运行时错误
#include <string>
使用MS VC++编译器时会发生错误,因为如果不这样做#include <string>,则无法operator<<定义std::string.
当编译器尝试编译时,ausgabe << f.getName();它会查找已operator<<定义的for std::string.由于未定义,编译器会寻找替代方案.有一个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<<的std::string时候被定义只<string>包括(与MS的编译器),因为这个原因,一切编译,但是你得到的多少有些意外的行为operator<<是越来越递归调用的MyClass,而不是调用operator<<的std::string.
这是否意味着通过
#include <iostream>字符串只包括部分?
不,完全包含字符串,否则您将无法使用它.
cbu*_*art 35
问题是你的代码正在进行无限递归.对于流媒体运营商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 <<':在所有控制路径上递归,函数将导致运行时堆栈溢出
| 归档时间: | 
 | 
| 查看次数: | 7251 次 | 
| 最近记录: |