Template Bug [modified]
-
In one of my header files, I had something like this:
class SomeOtherClass;
class SomeClass
{
private:
MyTemplateClass<someotherclass> instance;
};The compiler didn't complain. Using a forward declaration here in combination with a template was a bad idea. I compiled my program, ran it, and it crashed. Memory was getting corrupted somehow. I'd move things around in my code, set break points, etc... none of which seemed to help or shed any light on the problem. Eventually, I narrowed it down to one or two ares of my code. I looked at some of my code that ran ok and compared it to the troublesome code. That's when I spotted the forward declaration. The solution is to include the header file for the type being used with the template class. Not surprisingly, this it to tell the compiler information it needs to instantiate the instance member. I can only guess that the class wasn't being properly constructed before making the correction. I wasted a whole afternoon on this. :doh:
modified on Thursday, August 28, 2008 9:56 AM
-
In one of my header files, I had something like this:
class SomeOtherClass;
class SomeClass
{
private:
MyTemplateClass<someotherclass> instance;
};The compiler didn't complain. Using a forward declaration here in combination with a template was a bad idea. I compiled my program, ran it, and it crashed. Memory was getting corrupted somehow. I'd move things around in my code, set break points, etc... none of which seemed to help or shed any light on the problem. Eventually, I narrowed it down to one or two ares of my code. I looked at some of my code that ran ok and compared it to the troublesome code. That's when I spotted the forward declaration. The solution is to include the header file for the type being used with the template class. Not surprisingly, this it to tell the compiler information it needs to instantiate the instance member. I can only guess that the class wasn't being properly constructed before making the correction. I wasted a whole afternoon on this. :doh:
modified on Thursday, August 28, 2008 9:56 AM
Grrr, I must have screwed up the closing pre tag, as a result I can't edit my post.
-
Grrr, I must have screwed up the closing pre tag, as a result I can't edit my post.
And no one can read it.
-
And no one can read it.
PIEBALDconsult wrote:
And no one can read it.
Talk about subtle bugs, so subtle it can't be read. :) I've posted a bug report to Chris in the suggestions/bugs forum. Hopefully, the post will get fixed soon.
-
PIEBALDconsult wrote:
And no one can read it.
Talk about subtle bugs, so subtle it can't be read. :) I've posted a bug report to Chris in the suggestions/bugs forum. Hopefully, the post will get fixed soon.
Leslie Sanford wrote:
Talk about subtle bugs, so subtle it can't be read.
Lol. But shouldn't the compiler catch this kind of thing? Or am I hopelessly oversimplifying the manifold problems that compiling templates must present to the compiler writer? I had something everso vaguely similar recently. *Never* call a virtual function from your contructor (or from any method called from your constructor). It always calls the method in the base class. This is done for good reasons and is a documented C++ 'feature' (please provide a link someone!) but it sure had me going for a while, until a dim memory stirred. I guess it's hard for the compiler to check for this as the various methods in the call chain might be in different source files. Still a bear pit for the unwary though. Microsoft's fancy code-generating linker could do it though. Or maybe some kind of (optional) runtime check could be provided (e.g. emit code at the start of all virtual functions to check that
this->_in_constructor
is false). [Edit] Thinking about it a little bit, I think I can see where the compiler might be tripping up. You can, in my experience, write all sorts of garbage in templated code and the compiler doesn't give a monkeys. Only when you instantiate it does the compiler start to complain, by which time the cause can be a little obscure and the resulting (long!) error message is not always that edifying. So maybe the compiler had to 'put off' deciding if there was some kind of problem with your code and then (like most of us) never got around to finishing the job. Just a thought. [/Edit]Paul Sanders http://www.alpinesoft.co.uk
-
Leslie Sanford wrote:
Talk about subtle bugs, so subtle it can't be read.
Lol. But shouldn't the compiler catch this kind of thing? Or am I hopelessly oversimplifying the manifold problems that compiling templates must present to the compiler writer? I had something everso vaguely similar recently. *Never* call a virtual function from your contructor (or from any method called from your constructor). It always calls the method in the base class. This is done for good reasons and is a documented C++ 'feature' (please provide a link someone!) but it sure had me going for a while, until a dim memory stirred. I guess it's hard for the compiler to check for this as the various methods in the call chain might be in different source files. Still a bear pit for the unwary though. Microsoft's fancy code-generating linker could do it though. Or maybe some kind of (optional) runtime check could be provided (e.g. emit code at the start of all virtual functions to check that
this->_in_constructor
is false). [Edit] Thinking about it a little bit, I think I can see where the compiler might be tripping up. You can, in my experience, write all sorts of garbage in templated code and the compiler doesn't give a monkeys. Only when you instantiate it does the compiler start to complain, by which time the cause can be a little obscure and the resulting (long!) error message is not always that edifying. So maybe the compiler had to 'put off' deciding if there was some kind of problem with your code and then (like most of us) never got around to finishing the job. Just a thought. [/Edit]Paul Sanders http://www.alpinesoft.co.uk
Paul Sanders (AlpineSoft) wrote:
I had something everso vaguely similar recently. *Never* call a virtual function from your contructor (or from any method called from your constructor). It always calls the method in the base class. This is done for good reasons and is a documented C++ 'feature' (please provide a link someone!) but it sure had me going for a while, until a dim memory stirred.
Yup. It's even more dangerous with pure virtual methods. On a few rare occasions when running a commercial app, I'll get an error message that says something like "Pure virtual call something, something..." When I see that, I know that the developer called a pure virtual method from within the base class's constructor. Oops!! At that point, the virtual table hasn't been completely initialized, so calling a pure virtual method from within the class's constructor causes an exception to be thrown.
class MyClass
{
public:
MyClass()
{
// Ack!!
DoSomething();
}virtual void DoSomething() = 0;
};
-
Paul Sanders (AlpineSoft) wrote:
I had something everso vaguely similar recently. *Never* call a virtual function from your contructor (or from any method called from your constructor). It always calls the method in the base class. This is done for good reasons and is a documented C++ 'feature' (please provide a link someone!) but it sure had me going for a while, until a dim memory stirred.
Yup. It's even more dangerous with pure virtual methods. On a few rare occasions when running a commercial app, I'll get an error message that says something like "Pure virtual call something, something..." When I see that, I know that the developer called a pure virtual method from within the base class's constructor. Oops!! At that point, the virtual table hasn't been completely initialized, so calling a pure virtual method from within the class's constructor causes an exception to be thrown.
class MyClass
{
public:
MyClass()
{
// Ack!!
DoSomething();
}virtual void DoSomething() = 0;
};
Yes, I've had a few of those, and only recently did I figure out why. Live and learn, as they say. I would argue though that this is *less* dangerous than when a base implementation of the virtual function exists. Less subtle anyway. The vft is all set up by the time the constructor starts executing by the way, but it always gets passed a pointer to the one for the base class, even when you are constructing a derived object. The reason that Bjorn and his mates decided to do things this way is that the constructor of the derived class runs *after* that of the base class, so the derived object is in an unknown state (specifically, its instance variables will all be garbage) while the base class constructor is executing. Which brings me to yet another hobby horse of mine. The world would be (for me) a much (well, ok, slightly) happier place if you could say something like:
class MyClass = 0 { ... };
Meaning: set all my instance variables to zero before you call the constructor. So simple! Why on earth didn't they think of that? Or am I missing something obvious? I believe C# does precisely this, whether you want it to or not. Only reason not to is efficiency I guess, but since Joe Programmer is going to painstakingly initialise them all (to zero, mostly) one-by-one anyway, that doesn't really wash. It's the little things that make a difference, I always think.Paul Sanders http://www.alpinesoft.co.uk