Question

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.

Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top