Thursday, November 11, 2010

Why You Shouldn't Use Exception Specifications

I've significantly improved my coding style today...

I don't know if anyone else is guilty of this, but I have always used exception specifications religiously (see below if you are unsure as to what an exception specification is). I did this because of some very strange logic that now, looking back, seems very twisted.

My change of heart came about from reading a very well reasoned blog post. I thoroughly recommend that you read this as well if you like to use exception specifications.

Note
Example of an Exception Specification
double divide(int znumerator, int zdenominator) throw(std::invalid_argument) { if (zdenominator == 0) throw(std::invalid_argument("zdenominator cannot be 0")); return (double)znumerator / zdenominator; }

In the above code fragment, throw(std::invalid_argument) is the exception specification.

Monday, November 8, 2010

An Easy to Use Profiling Class

My professors always want profiling data...

It is really quite a bother to profile my code accurately. The explosion of timers and temporary variable always makes my code degenerate into an ugly mess.

The other day I decided to bite the bullet and make my own profiling library, one that I would truly enjoy using. I'm proud to say I finished yesterday, and I've put the finishing touches on it today.

My library adds very little code to your project and provides very accurate results. Rather than tell you all about my library, let's look at some quick examples to demonstrate how simple it is.

My Foo Function
void foo() { for (int i = 0; i < 99999; ++i) ; int q = 1; q *= (int)((4.3 * 23.43 * 23.454) / 234.32); }
My Foo Function With Profiling
void foo() { PF(); // Alias for PROFILE_FUNCTION() for (int i = 0; i < 99999; ++i) ; int q = 1; q *= (int)((4.3 * 23.43 * 23.454) / 234.32); }

As you can see, adding profiling into your code is a simple matter. Only one line of code required. If you were to execute that function, your program would automatically output the results of the profiling to the text file profile.txt when your program terminates (this is accomplished by a callback function added to the list of functions maintained by atexit()). And if you'd like to stop any profiling data from being collected, you may simply define NO_PROFILE at the top of your main.cpp file.

That's not the only thing you can do though, perhaps you'd like to profile a block of code, and not necessarily an entire function.

My Foo Function
void foo() { for (int i = 0; i < 99999; ++i) ; int q = 1; q *= (int)((4.3 * 23.43 * 23.454) / 234.32); }
My Foo Function With a Little Bit of Profiling
void foo() { for (int i = 0; i < 99999; ++i) ; PROFILE_CODE() { int q = 1; q *= (int)((4.3 * 23.43 * 23.454) / 234.32); } }

It's all very simple. There is even support for partitioning, however, I find it difficult to explain exactly what that means so I suggest taking a look at the main.cpp.txt file that is included with the header files to see a comprehensive overview of the features.

Below is some example profiling output. This is the output of the main.cpp.txt example file that is included with the header files.

~Profiling data output Mon Nov  8 15:01:45 2010

Profile for "Strange Char Operations"
 Ran in 0.000000 seconds. Tested 19900 times.
Profile for "The doMoreStuff() function"
 Ran in 0.006900 seconds. Tested 100 times.
Profile for "function doStuff()"
 Ran in 0.000063 seconds. Tested 10100 times.
Profile for "function linear()"
 Partition 0   ran in 0.000000 seconds. Tested 10  time(s).
 Partition 1   ran in 0.006000 seconds. Tested 10  time(s).
 Partition 2   ran in 0.005000 seconds. Tested 10  time(s).
 Partition 3   ran in 0.009000 seconds. Tested 10  time(s).
 Partition 4   ran in 0.013000 seconds. Tested 10  time(s).
 Partition 5   ran in 0.013000 seconds. Tested 10  time(s).
 Partition 6   ran in 0.017000 seconds. Tested 10  time(s).
 Partition 7   ran in 0.018000 seconds. Tested 10  time(s).
 Partition 8   ran in 0.022000 seconds. Tested 10  time(s).
 Partition 9   ran in 0.025000 seconds. Tested 10  time(s).
 Average time for each partition is 0.012800 seconds.
 Total time for all partitions is 0.128000 seconds.
Profile for "main.cpp @ 35"
 Ran in 0.000064 seconds. Tested 10000 times.

You can find the code here (updated 11/9/2010), simply extract the folder into your source tree and include profile/profile.h in your main.cpp file.

I will be constantly updating the library as I find problems and/or add new features. I encourage you to check back whenever you'd like to use it to see if there is an update out. Also, if you'd like, you may leave me your email and I will alert you to new updates.

As always, please email me or post here if you find any bugs in the code so I may fix them.

Wednesday, November 3, 2010

Initializing a Static Member Variable within a Templated Class which relies upon Template Parameters

I ran into a tree today...

I was writing this wonderful foo class and everything was going well, but then I encountered an interesting problem.

Bad
template<class T> class foo { static T bar; };

How can I properly initialize bar?

In order to initialize a static member variable in a templated class, you need to include the initialization within the class's header file along with the class's template definition.

Some code should speak louder than words...

Good
template<class T> class foo { static T bar; }; template<class T> T foo::bar = value;

You need to include the initialization within the header file because the compiler needs a templated class's complete definition whenever it's used, and the compiler can't know that the static member variable was ever initialized if its buried in some other .cpp file.

You need to include the template definition of the class because it looks strange otherwise. Realistically, I'm pretty sure, the compiler would do just fine without the information (it could retrieve it itself easily enough), but I figure that when the standard was being crafted they looked at both options and decided that it looked strange without.

Tuesday, November 2, 2010

Trying to Copy a std::ostream

I bumped into a particularly cryptic compiler error today...

undefined reference to `std::ios_base::ios_base(std::ios_base const&)'|

After some interesting debugging I came across the problem in my code.

The Problem
void print(std::ostream zout = std::cout) { /* Some Code */ }

Can you spot what the problem is?

Hopefully you noticed that I'm passing zout by value, and std::ostream doesn't have a copy constructor.

The Solution
void print(std::ostream &zout = std::cout) { /* Some Code */ }

If I pass zout as a reference the compiler accepts it without a word and the desired behavior is achieved.