Friday, February 29, 2008

std::min and std::max

Today I typed the following:
int t = (std::max)(timeout, lagtime);

Why did I put parentheses around std::max? Because windows.h defines (among other things) a max and a min macro. If you include windows.h the above code will not compile. For example the following:
#include "windows.h"
#include <algorithm>

void foo() {
int i = 5;
int j = 7;
int x = std::max(i,j);
}

Will produce the following error with Visual Studio C++ 2005:
1>test.cpp(7) : error C2589: '(' : illegal token on right side of '::'
1>test.cpp(7) : error C2143: syntax error : missing ';' before '::'

There are a number of ways to work around windows.h defining these two macros.

  • Use alternative names defined in windows.h.
    int x = _cpp_max(i,j);
    int y = _cpp_min(i,j);
    This is not portable; only works on Windows.

  • Define NOMINMAX before including windows.h. This might break existing code that assumes NOMINMAX is not defined.

  • Don't use std::min and std::max. Instead use the tertiary operator like so:
    int x = i > j ? i : j; // max(i,j)
    int y = i < j ? i : j; // min(i,j)
    This is portable but not as readable and more error prone.

  • Use using statements to make the code portable:
    using std::min;
    using std::max;
    int x = max(i,j);
    int y = min(i,j);
    This works but requires two more lines of code. You could also just use 'using namespace std;' but that might pull in more than you want.

  • Use std::min<int> and std::max<int>
    int x = std::max<int>(i,j);
    int y = std::min<int>(i,j);
    This requires you to specify the type. However in some cases this actually helps. For example:
    int i = 5;
    unsigned int j = 7;
    int x = (std::max)(i,j);
    int y = (std::min)(i,j);
    Note the 'unsigned'. Generates the following errors:
    1>test.cpp(7) : error C2780: 'const _Ty &std::max(const _Ty &,const _Ty &,_Pr)' : 
    expects 3 arguments - 2 provided
    1> c:\program files\microsoft visual studio 8\vc\include\xutility(3190) :
    see declaration of 'std::max'
    1>test.cpp(7) : error C2782: 'const _Ty &std::max(const _Ty &,const _Ty &)' :
    template parameter '_Ty' is ambiguous
    1> c:\program files\microsoft visual studio 8\vc\include\xutility(3182) :
    see declaration of 'std::max'
    1> could be 'unsigned int'
    1> or 'int'
    By explicitly specifying type via <int> you remove the ambiguity.

  • Use (std::min) and (std::max)
    int i = 5;
    int j = 7;
    int x = (std::max)(i,j);
    int y = (std::min)(i,j);
    This works (as does the std::max<int>) because the C++ preprocessor requires '(' as the next preprocessing token following the macro name to preform the macro expansion.

Thursday, February 28, 2008

C++ if variable initialization

All C++ programmer know that a variable can be initialized within the definition of a for statement like so:
for (int i = 0; i < 9; ++i) {  
std::cout << i << '\n';
}
However, many do not know that the same can be done in an if statement. For example:
if (Foo* f = dynamic_cast<Foo*>(a)) {
f->doSomething();
}

// f is not available here.
You should always define your variables to have the smallest possible scope. This technique allows you to pull your local if variables into the if statement thereby reducing their visibility.

Monday, February 25, 2008

std::fill_n

Many of the tests I have been writing lately involve creating min/max/misc. values to send across our messaging system. It dawned on me today that the for loops I have been writing could be better expressed with std::fill_n. For example take the following loop:
std::vector<std::string> strSeq;
const int MAX_STRSEQ_SIZE = 31;
for (int i = 0; i < MAX_STRSEQ_SIZE; ++i)
strSeq.push_back("0123456789");
This can be better written using the standard template library:
std::vector<std::string> strSeq;
const int MAX_STRSEQ_SIZE = 31;
std::fill_n(std::back_inserter(strSeq), MAX_STRSEQ_SIZE,
"0123456789");
Although this isn't really any shorter than the original for loop, I believe it reads better.

Lets review std::fill_n():
template<typename ForwardIter, typename Size, typename T>
fill_n(ForwardIter begin, Size n, const T& value);
std::fill_n takes three arguments: ForwardIter, Size, and T. ForwardIter is designed to take an iterator pointing to where to begin filling. However, since std::fill_n assumes there is room in the container we use std::back_inserter() to adapt the assignment operator into a push_back on our container. Size is how many of T to assign and T is the value to assign.

Friday, February 22, 2008

Next-Gen PC Design Competition

I you have not already done so, hop over and check out some of these great designs and vote for you favorite.

Next-Gen PC Design Competition

I voted for the FluxPC.

Wednesday, February 20, 2008

Providence Christian Academy Website

Since moving to Pensacola in June 2007 my kids old school, Providence Christian Academy has redone their website from when I maintained it. Here is a link to the old version Providence Christian Academy. I think the current one is better than the one I hacked together.

What do you think?

Monday, February 11, 2008

Internet Browser Crashing

Update:
It now appears re-installing Java did not fix my problems. My crashes are back and they are worse than ever. I'm beginning to think it may be a hardware problem. I booted with a Knoppix Linux CD and tried Firefox from there. It also crashed multiple times.

Original Post:
For many months I have suffered from an unstable Windows XP. Firefox, IE, Safari, Opera, Thunderbird, Windows Media Player, QuickBooks, and every other program that dared attempt to access the internet would periodically crash (Microsoft Debug Window) or simply just disappear. If I attempted to debug using Visual Studio 7.1 or 8, Visual Studio would crash with a Microsoft Debug Window (not very helpful). I looked in the event viewer many times but never found anything. I ran many different kinds of virus and spyware removal tools. Nothing could be found to fix my problems. I, of course, Googled my problem many times and never found anything.

The most annoying thing was doing my online banking (and having the browser crash while trying to purchase something). I was unable to access Bank of America from any browser except Safari. Safari would also crash, just less often. Other browsers might work for a few pages but would always crash more often than Safari. IE was the worse. I could hardly go to any pages without IE crashing. Firefox (my browser of choice) was mostly stable. It however would crash multiple times a day. This was bearable because Firefox would restart exactly where I left it with all my tabs ready to go.

I kept telling myself that I would re-install Windows XP when my current project ended. I didn't want to risk making it worse since I use VSClient and VNC everyday to access a remote computer for work. VNC never crashed.

However, the other day I started doing my taxes. I have used TurboTax online for many years. So I fire up Firefox and access TurboTax only to have it crash almost immediately. Same for Safari. Ugh! It was the straw that broke the camels back. I dug out my Windows XP CD and kicked off a re-install. Hours later, I finally have Windows XP reinstalled. This was after having to call Microsoft to activate Windows XP since the activation window crashed trying to access the internet. Not a good sign. And as you may have guessed by now, this didn't help one bit. The only difference I saw was that the icons in Bloglines have now disappeared; replaced with the text 'expand folder' and 'collapse folder'.

Now I'm really frustrated. I just knew the re-install of Windows XP would fix the problem. At this point I'm starting to think the only remedy will be to start from scratch with a clean install of Windows XP (or maybe Linux). However, I use Visual Studio and QuickBooks and other Windows only applications.

Back to Googling. I ran across this site: IE crashes at certain web-sites. It recommends re-installing Java. So I follow their link and grab Java and re-install it. This seems to fix most, but not quite all, of my problems. I can now access TurboTax and Bank of America from Firefox without it ever crashing.

I re-installed Java about a week ago. Firefox has only crashed on me twice since then. Thunderbird has crashed a few times (this might not be related, not sure). QuickBooks now can access the internet (very important since I had to register it). Windows Media Player has not crashed since. And IE seems to actually work now. I use Firefox almost exclusively, however. So I think I'm mostly back to normal. I assume other folks have a few crashes here and there.