Thursday, June 7, 2007

Careful with those stubs, mister!

This is just a tiny snippet which ties into my last post about compiler warnings.

Frequently when I'm building a class, I'll stub out a lot of the functions just to get an idea of how things will work. "Stubbing" simply means adding the function declaration/definitions, but instead of having the function actually perform it's task, it's usually either left blank, or does a print statement to show where the control is currently at. That's all fine and well...until you do something like I did.

In order to complete my stubbing, I went as far as to assign one of my class data members, an std::vector<>, to the return of the function that would be used to populate this vector. The problem? While stubbing that said function, I forgot to add a return value! This, coupled with lack of any compiler warning flags, caused a segfault when I ran some testing code.

Now, to the heart of the matter: Why was this so hard for me to track down, aside from improper (absent) warning flags? I was doing my debug print statements with std::cout. The problem? std::cout is buffered, which means things get printed when the OS decides they get printed, not exactly when you tell it to print. After I tried to initialize my vector from the function (of which returned nothing), I made a call to some other class functions, and due to the buffering of my debug statements, it seemed the segfault happened AFTER that other class function returned, but BEFORE control was given back to the constructor that called it. This clearly made no sense, and all of the code looked fine.

Using std::cerr is the optimal choice for debugging output because it gets printed exactly when you tell it to. More importantly, a simple -Wall flag to g++ would have informed me right away that: "control reaches end of non-void function" and immediately I'd know why my program was segfaulting.

So, lessons learned?

1. Enable. Compiler. Warnings.
2. Use std::cerr for debugging output
3. Complete your stubbed functions with return values and proper parameters

Note: I've been told that using std::endl will force std::cout to be printed, but for whatever reason that just wasn't happening for me. *shrug*

4 comments:

Allen Madsen said...

I've noticed some interesting things when generating stubs in with IDE's such as Eclipse and .Net. When Eclipse generates new stubs it puts a TODO task item into the stub along the lines of "//TODO - this stub was auto generated" and because it has this comment in it, there is special highlighting to signify that the method has not been implemented yet. In .Net it employs a very direct approach to get your attention that you have not implemented a method. When you auto-generate a method in .Net it inserts a exception being thrown that says the method has not been implemented. So if you run your program and reach a place where you call an unimplemented method, you will get an exception telling you so.

owner said...

Yeah, that seems to be one of the hand-holding qualities of .Net, which isn't at all a bad thing. I haven't done much with IDE's in terms of extensive code generation or anything like that, though. Probably should start, but I just feel "removed" from the code if I'm not typing a majority of it myself. I like IDE's for things such as syntax highlighting, bracket matching, code formatting, etc...

Allen Madsen said...

I think IDE's let you concentrate on the important parts of coding. Especially with generating code for you. If you think about it, what kind of code could a IDE generate for you? Not something complex, because there is no way it can know what your program is going to do. The job of the IDE is to make all of those simple mundane tasks even simpler and less mundane. For example, whenever you're writing a method and you realize you need another method so that the method you are writing can call that one. Why would you want to stop what you are doing and go write that method and lose your train of thought. The power of an IDE is that you can write that method as if it exists and have it generate a stub for you which you can come back to later and write. If a task I need to do is stupid enough a computer can do it, I'm all for it. Why should I spend my time on something that simple when there are more complex items to concentrate on?

Teli said...

Great work.