简体   繁体   中英

Visual Studio 2008 run-time stack overflow warning when operator< recursive on all paths

The C++ code below generates the following warning in Visual Studio 2008:

1>c:...\\sample.cpp(6) : warning C4717: 'operator<' : recursive on all control paths, function will > cause runtime stack overflow

If I use the Sample class on any situation that the needs operator<, it actually crashes with a stack overflow error (for example after inserting the second Sample object in a multiset). The constructor keeps being called until it runs out of stack space.

The code below is all that's needed to generate the warning on its own (without anything in the code referencing the Sample class).

// 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;
}

The warning shows with VC++ and VS2008 (Win32, /W3) on Win7. For the same platform and exactly the same code, but with MinGW GCC 4.7.3 on eclipse, I don't get any warning.

If I add the < string > header the warning disappears in VS2008 and any use of the Sample class works perfectly fine.

Also, if I declare the Sample constructor explicit, VS2008 throws the following compile error:

1>.\\Sample.cpp(5) : error C2678: binary '<' : no operator found which takes a left-hand operand of > type 'const std::string' (or there is no acceptable conversion) 1> c:...\\Sample.hpp(13): could be 'bool operator <(const Sample &,const Sample &)' 1> while trying to match the argument list '(const std::string, const std::string)'

However, setting the constructor explicit in GCC still doesn't generate any warnings nor errors (I set the warnings in Eclipse to the most comprehensive levels I could).

I'd like to know if someone can please roughly explain how VS2008 determines when to generate this stack overflow warning. In this case, it turns out to be correct so I'm curious to see how it's done. Also, if possible, why GCC behaves differently here please. Hopefully this makes sense.

This is happening because at the point of comparison std::string is an incomplete type and the conversion constructor Sample (std::string id) is being implicitly invoked. In the expression s1.ID<s2.ID both the LHS and RHS are being implicitly converted to a temporary Sample and the conversion operator then gets called again (and again and again).

You need to include <string> so the complete definition of std::string is visible and I highly recommend declaring the constructor of sample explicit .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM