下面的C ++代码在Visual Studio 2008中生成以下警告:
1> c:... \ sample.cpp(6):警告C4717:'operator<' :在所有控制路径上递归,函数将>导致运行时堆栈溢出
如果我在需要运算符<的任何情况下使用Sample类,它实际上会因堆栈溢出错误而崩溃(例如在多个集合中插入第二个Sample对象之后)。构造函数一直被调用,直到它用完堆栈空间。
以下代码是自己生成警告所需的全部内容(代码中没有引用Sample类的任何内容)。
// Sample.hpp
#include <iostream>
class __declspec(dllexport) Sample
{
std::string ID;
public:
Sample (std::string id):ID(id) {};
friend bool __declspec(dllexport) operator<(const Sample& s1, const Sample& s2);
};
// Sample.cpp
#include "Sample.hpp"
bool operator<(const Sample& s1, const Sample& s2)
{
return s1.ID<s2.ID;
}
警告在Win7上显示VC ++和VS2008(Win32,/ W3)。对于相同的平台和完全相同的代码,但在eclipse上使用MinGW GCC 4.7.3,我没有得到任何警告。
如果我添加&lt;字符串&gt;标题警告在VS2008中消失,任何使用Sample类都可以正常工作。
此外,如果我声明Sample构造函数是显式的,VS2008会抛出以下编译错误:
1&gt;。\ Sample.cpp(5):错误C2678:二进制'&lt;' :找不到哪个运算符采用&gt;的左手操作数输入'const std :: string'(或者没有可接受的转换) 1 GT; c:... \ Sample.hpp(13):可能是'bool operator&lt;(const Sample&amp;,const Sample&amp;)' 1 GT;在尝试匹配参数列表'(const std :: string,const std :: string)'
时
但是,在GCC中显式设置构造函数仍然不会生成任何警告或错误(我将Eclipse中的警告设置为最全面的级别)。
我想知道是否有人能够大致解释VS2008如何确定何时生成此堆栈溢出警告。在这种情况下,它证明是正确的,所以我很想知道它是如何完成的。另外,如果可能的话,为什么GCC在这方面表现不同。希望这是有道理的。
答案 0 :(得分:3)
这种情况正在发生,因为在比较时std::string
是一个不完整的类型,转换构造函数Sample (std::string id)
正在隐式调用。在表达式s1.ID<s2.ID
中,LHS和RHS都被隐式转换为临时Sample
,然后再次调用转换运算符(并且一次又一次)。
您需要添加<string>
,以便std::string
的完整定义可见和我强烈建议您声明样本explicit
的构造函数。