1

下面的 C++ 代码在 Visual Studio 2008 中生成以下警告:

1>c:...\sample.cpp(6) : 警告 C4717: 'operator<' : 在所有控制路径上递归,函数将 > 导致运行时堆栈溢出

如果我在需要 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,我没有收到任何警告。

如果我添加 < string > 标题,则警告在 VS2008 中消失,并且 Sample 类的任何使用都可以正常工作。

此外,如果我显式声明 Sample 构造函数,VS2008 会引发以下编译错误:

1>.\Sample.cpp(5) : error C2678: binary '<' : no operator found which takes a left-hand operand of > type 'const std::string' (或没有可接受的转换) 1> c :...\Sample.hpp(13): 可能是 'bool operator <(const Sample &,const Sample &)' 1> 尝试匹配参数列表 '(const std::string, const std::string )'

但是,在 GCC 中显式设置构造函数仍然不会产生任何警告或错误(我将 Eclipse 中的警告设置为我能做到的最全面的级别)。

我想知道是否有人可以大致解释一下VS2008如何确定何时生成此堆栈溢出警告。在这种情况下,事实证明它是正确的,所以我很想知道它是如何完成的。另外,如果可能的话,为什么 GCC 在这里表现不同。希望这是有道理的。

4

1 回答 1

3

发生这种情况是因为在比较点是不完整的类型,并且正在隐式调用std::string转换构造函数。在表达式中,LHS 和 RHS 都被隐式转换为临时变量,然后再次调用转换运算符(一次又一次)。Sample (std::string id)s1.ID<s2.IDSample

您需要包含<string>完整的定义,因此std::string强烈建议您声明 sample 的构造函数。explicit

于 2013-08-04T00:28:22.253 回答