views:

100

answers:

3

I've found this strange behavior with VS2005 C++ compiler. Here is the situation:

I cannot publish the code, but situation is very simple.

Here is initial code: it work perfectly

class Foo {
     public:
     Foo(Bar &bar) { ... }
}

The constructor implementation stores a reference, setup some members... indeed nothing special.

If I change the code in the following way:

class Foo {
     public:
     Foo(const Bar &bar) { ... }
}

I've added a const qualifier to the only constructor routine parameter.

It compiles correctly, but the compiler outputs a warning saying that the routine Foo::Foo will cause a stackoverflow (even if the execution path doesn't construct any object Foo); effectively this happens.

So, why the code without the const parameter works perfectly, while the one with the const qualifier causes a stackoverflow? What can cause this strange behavior?

+2  A: 

The only way for this to cause a stack overflow (besides a bug in the compiler, which, in my 15 years of doing C++, I have found rare compared to my own errors) is that Foo(const Bar&) creates a Foo object passing it a Bar object. Bugs like these can be subtle and hard to find by looking at the code.

But if you have VS2005, you have a pretty good debugger at hand. Put a breakpoint into that constructor, run the program until you hit the breakpoint, then run again until you hit the breakpoint the second time. Examination of the stack will show you how it happens.

If not every call to this constructor will cause a stack overflow, you can add this code:

namespace { unsigned int recursion_detector = 0; }

Foo::foo(const Bar& bar)
{
  if(recursion_detector++)
    ++recursion_detector; // meaningless code just to put a breakpoint here
  // rest of constructor code
}

and put a breakpoint on the line indicated, which will be hit when the recursion occurs.

sbi
+4  A: 

Try usng the explicit keyword?

My guess is that, with const, you're declaring an automatic conversion from Bar to Foo; and if you already have any similarly automatic conversion from Foo to Bar, then overflow?

ChrisW
A: 

You could change the parameter from const Bar &bar to const Bar *bar. It will work fine, you would just have to change the way you manage the parameter bar (from a referente to a pointer).

The object initialization would be something like:

Bar mybar;

...

Foo myfoo(&mybar);


class Foo {
     public:
     Foo(const Bar *bar) { ... }
};

It's not that bad...

Jorg B Jorge