Mark Nelson

Dr. Dobb's Bloggers

I (Still) Love C++

May 19, 2009

I love C++, no question about it. But loving C++ is like being a Yankees fan. Yes, you get a lot of wins, and see some great performances. But at the same time you’re always apologizing when your heroes turn out to have feet of clay.

A couple of painful shortcomings of C++ were brought home to me pretty clearly when I worked on a solution to Problem 96 at Project Euler, Solving Sudoku.

The Goal

I wasn’t too worried about getting a solution to Sudoko – what I was really trying to do was write a program that was short, easy to follow, and reasonably efficient.

The easiest way to do this seemed to be to use a simple brute force recursive approach: for a given grid, simply fill in the first open square with each of its possible values, then recursively try to solve the resulting grid.

The process of checking for the validity of a given cell placement is the tricky part. When solving as a human, you probably quickly scan the grid looking for collisions in the row, column, and block. While the human eye and brain are really good at that type of scan, brute force of that kind on the computer would be pretty expensive.

To speed up the checking process, I created 27 set objects, one for each row, column, and block. I initially seeded these sets with all 9 integer values. As each cell is placed on the grid, the corresponding values are removed from three of these sets.

The First Weakness

This brings upone of the first problems with C++. The code for using some of these data structures is awkward, wordy, and not particularly easy to read.

As an example, it would be really useful for me to be able to perform the intersection of the row, column, and block sets for a given cell.What I want to be able to do is something like this:

std::set<int> result = row[ i] & col[ i] & block[ i ];

What you get instead is maybe 4 lines of dense code involving function calls with huge numbers of arguments. Code that is clearly write-only, and pretty hard to defend.

Efficiency

Nonetheless, I got my program to run properly, and while code like that shown in the fragment below won’t win any prizes for clarity, it produced the results I wanted.

for ( int test_val = 1 ; test_val <= 9 ; test_val++ ) {

std::set<int>::iterator ii =

rows[ rowset[ cell ] ].find( test_val );

if ( ii == rows[ rowset[ cell ] ].end() )

continue;

std::set<int>::iterator jj =

cols[ colset[ cell ] ].find( test_val );

if ( jj == cols[ colset[ cell ] ].end() )

continue;

std::set<int>::iterator kk =

boxes[ boxset[ cell ] ].find( test_val );

if ( kk == boxes[ boxset[ cell ] ].end() )

continue;

grid[ cell ] = test_val;

However, I was a little disappointed in the performance of the program. Solving all 50 of Project Euler’s sample puzzles took 2 minutes in debug mode (in which a lot of extra checking of iterators and the like takes place.)The release build was more reasonable, but still took 3.7s.

So I thought this would be time for a good experiment to see if the vintage STL components generate as much overhead as the naysayers would have us believe. I replaced the set<int>data structures with simple integers used as a bit vector. My set operations now were simple ANDs and ORs of single bits. And the set intersection code was suddenly exactly what I wanted.

The result?The release code now runs in .3s instead of 3.7s. A ten-fold improvement.

Now there are many times when that ten-fold improvement is not a big deal. But when it’s found in the 10% of your code where the program spends 90% of its time, it seems to add up.

I have to remind myself, as a poster on Digg pointed out, the only things Linus does like is Linux, Git, and KDE (or is it Gnome?)

The important thing, I think, is to understand your language’s weaknesses as well or better than its detractors do.Maybe you won’t win any arguments with this strategy, but you might write better code.

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task.
However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

Video

This month's Dr. Dobb's Journal

This month,
Dr. Dobb's Journal is devoted to mobile programming. We introduce you to Apple's new Swift programming language, discuss the perils of being the third-most-popular mobile platform, revisit SQLite on Android
, and much more!