Archive for the ‘C++’ Category.

Goodbye, dmr…

#include <stdio.h>

int main ()
{
    printf ("goodbye, dad.\n");
    return 0;
}

VN:F [1.9.13_1145]
Rating: 9.7/10 (6 votes cast)
VN:F [1.9.13_1145]
Rating: +7 (from 7 votes)

C++11?

The C++0x standard has been approved by ISO/IEC. This probably means that we’re going to be calling this iteration of the language C++11.

It amazes me how much of the language and the standard library people don’t use already. And I mean the C++98 stuff that has been around for 13 fracking years! True, there are professional developers that decide to use a specific subset of the language, or in some situations some design decisions are “inherited” by programmers working on an existing body of code… but I’m not bitching about them (much!) I’m talking about programmers and their new projects and sample code. New programmers (usually university or high school students) don’t learn about most of C++ because their teachers don’t know them and that almost all programming books on C++ suck (sometimes, it’s not the author’s fault; C++ is just too vast and complex.) More “experienced” programmers usually learn about a subset of the language and form a “comfort zone” and stay in there; because anything out of that zone will upset them. The bad thing is that this C++ comfort zone is – more often than not – way too small.

It might (or might not) include good polymorphism and class hierarchies (which I don’t like, incidentally) but almost always it does not include any meaningful use of generic programming, higher order and (some vestiges of) functional programming, attention to memory and layout (I believe many non-trivial programs have ran or are running into address-space limitations as we speak,) exception-safe and exception-correct programming, development of domain-specific mini-languages, real scalability and thread-correctness, etc.

Of course, everybody is free to program the way they want or can. I’m not the one to judge. All I’m saying is that even in the single language we use, there is much that we don’t take advantage of (let alone using other languages that might be more suitable for a job.)

Now, enters a new and feature-rich standard of C++ into an already starved expertise pool. There are so many real features and improvements in this iteration of the standard that they could overwhelm at the first glance. There is (just off the top of my head) r-value references and perfect forwarding, lambdas, variadic templates, compile-time constant expressions, user-defined literals, better enumerations, typedefing templates, initializer lists, better control over inherited methods, better control over compiler-generated class methods, finally some semblance of class- and method-specific directives (alignment, etc.,) extern templates, forwarding constructors, initializing class data members upon declaration, auto and decltype keywords for type inference and whatnot, (oh, I almost forgot!) the cool and hip new way of declaring the return type of a function, and much more.

The above features are just the ones that I could recall right now and in the core language only. I need and want to use these features, additions and improvements right now. They all make my code better and my life easier. These are not some obscure features for practitioners of “black magic”. They benefit the likes of you and I, not language lawyers, but people with real applications and real problems.

I guess what I’m saying is that as a C++ programmer, you should not be afraid of experimenting with the new features today. Don’t wait for the books or libraries and frameworks to pick them up. Books will take years and they will be all wrong and useless anyways (of course, with a couple of stellar exceptions.) Again, only with a few exceptions, libraries and frameworks will be burdened with incompetence, corporate politics, backward and forward compatibility and compiler compatibility (with the most brain-dead compilers. Please don’t rely on Qt or wxWidgets or whatever to do your C++ for you. Please don’t wait for Deitel and Deitel to teach you C++.

Start with Wikipedia. Read various texts and tutorials and overviews that uncle Google finds for you. Start experimenting and teaching yourselves the new features of C++11; and any of the old feature-set that you might be rusty about. It’s a great time for C++, as it is now a better language than it ever was. It’s probably the best general purpose programming language out there for people with actual hardware limitations on their applications. And it can do practically everything. (Also, C++ supports the widest range and mixture of programming paradigms of any programming language that I know of.)

Notes: I have three points to add to the above rant.

First is about the advancements in the standard library. They are much more substantial and accessible for the lazy programmer (I don’t use the term “lazy programmer” as a negative phrase!) as most of the additions are already available with the most popular compilers, or even in Boost if your compiler doesn’t have them yet or if you don’t like your compiler vendor’s standard library! I’m much less enthusiastic about the new C++ standard library features simply because most of them have been available as part of Boost for years and therefore are hardly new. Still exciting, though!

Second. No compiler that I work with has support for all or even most of the new core language features, although GCC is close (not to “all”, but it is close to “much”.) The state of support in Microsoft’s Visual C++ is closer to pathetic. Intel C++’s condition is not much better either. A partial table of the state of support for various new features of the language across quite a few compilers can be found here. Right now, I (and probably everyone else) would suggest using GCC. Get your hands on 4.7 if you can, or use 4.6 or even 4.5. Good luck!

It seems that I’ve forgotten my third note! Maybe it’d come to me later.

VN:F [1.9.13_1145]
Rating: 10.0/10 (4 votes cast)
VN:F [1.9.13_1145]
Rating: +3 (from 3 votes)

Fibonacci Numbers and Bad Teachers

Recursion is a fascinating and essential idea in mathematics, programming and design (among other things.) As a programmer, if you don’t understand this very simple idea (and I mean really understand it) you are pretty much done for. While it’s not a hard concept for any half-intelligent person to grasp, I don’t exactly know how many of us really do grasp it. But it’s not what I’m going to bitch about today.

In programming courses, one of the first examples used to introduce the idea of recursion is the Fibonacci sequence. You know, the series of integers starting with 0 and 1, where every next number is the sum of the two previous ones. (OK, I know that you do know. I was just covering all my bases.)

Anyways, the most simple and elegant introductory way of implementing a function that returns the nth number in the Fibonacci series goes something like this:

1
2
3
4
5
6
7
// Just making things clear!
typedef unsigned long long Integer;
 
Integer Fib (unsigned n)
{
	return n < 2 ? n : Fib(n - 2) + Fib(n - 1);
}

And every half-descent programmer knows that that’s probably one of the worst ways you can implement the idea. I’m not kidding. The teachers just throw this at the students, and the brighter of the students see the elegance and simple beauty of it and it will take years for most of them to realize the problems with this particular implementation. Some of them never do. This implementation performs very poorly for even the small values of n, which of course should be apparent when you contemplate its time complexity and recursion tree (I won’t go into space considerations, because they are not much of a problem until n goes into (many) thousands, at which point the value of the function becomes larger than you can store naively in most languages, which means you should have already given space considerations a serious thought.)

But even later, when the students learn about complexity analysis and Big O notation and crap like that, more often than not, they fail to apply the newly acquired knowledge to the old beliefs. If the teacher is good, and the student is bright and lucky enough, they walk out of their algorithm and data structure course with the new belief that bubble sort is bad, hash tables are good, and disk seek times dominate everything else (all of which are obviously bullshit in the absolute sense.)

For the more astute reader, I need to clarify that the badness of the mentioned implementation stems from the fact that most common languages (including C++) are mainly side-effect-driven languages, in that they rely mostly on the side-effects of expressions and statements to get the intended job done (the usage of the term “statement” is a clear sign of that.) Otherwise, you wouldn’t see so much assignment in our code. A functional and side-effect-free programming language (or more accurately, programming model) could easily cache the result of each invocation of the Fib function for any particular n (because the function call would be without side effects and therefore time-invariant) and would not need to evaluate any Fib(n) more than once. This is something that is being done in some of the better implementations of functional languages, AFAIK.

To emulate this behavior in this case, one can use a hand-coded version of what is known as Memoization, a la:

1
2
3
4
5
6
7
8
9
10
11
12
13
Integer Fib (unsigned n)
{
	static std::vector<integer> Mem;
	if (n < Mem.size() && 0 != Mem[n]) return Mem[n];  // The second condition is redundant, right?
 
	Integer ret = n < 2 ? n : Fib(n - 1) + Fib(n - 2);
 
	if (n >= Mem.size()) Mem.resize (n + 1, 0);
	Mem[n] = ret;
 
	return ret;
}
</integer>

This is not a bad implementation. It does have some issues in multithreaded applications, but I'm willing to overlook that for now. This implementation is linear in both time and space, and it can be faster than simple non-recursive implementations because it never calculates any Fib(n) more than once over the whole lifetime of the process. But it's not pretty (it has its charms, though!) and this way of doing things is error-prone (because you are adding memory and bookkeeping to a mathematical construct that is otherwise free of this stuff.) Not to mention that it is basically impossible to use as an introductory example; because it needs knowledge from all over the map.

A better implementation might be:

1
2
3
4
5
6
7
8
9
10
11
12
13
std::pair<integer , Integer> _fib (unsigned n)
{
	if (n < 2) return std::make_pair(n, 0);
 
	std::pair<Integer, Integer> Fn_1 = _fib(n - 1);
	return std::make_pair(Fn_1.first + Fn_1.second, Fn_1.first);
}
 
Integer Fib (unsigned n)
{
	return _fib(n).first;
}
</integer>

Of course, the meat of this implementation (such as it is) is the _fib function. The other one is just there to present a nicer and more consistent interface. Let me be the first one to say that there are more ways to implement a better Fibonacci and still stay essentially recursive. This is just one way, and not a particularly great one. But it's not bad either.

Now, how come no programming instructor ever teaches the likes of this implementation? Not the ones I studied under, at least. Are they afraid that their students' heads are going to explode? PROGRAMMING IS HARD PEOPLE! If a programmer can't handle a substantial improvement over a bad implementation of a simple idea, they are in for a big (and not at all nice) surprise. I hereby beg any teachers, instructors, professors and whatnot that have anything to do with teaching starting programmers to quit treating them like idiots, because idiots won't make good programmers. The idiots are not going to understand what they need anyways, so why take the chance of profound understanding from those who have the capacity to learn, but might not if you treat them like babies?

For the sake of completeness, here's a non-recursive implementation:

1
2
3
4
5
6
7
8
9
10
11
12
13
Integer Fib (unsigned n)
{
	if (0 == n) return 0;
 
	Integer last = 1, penultimate = 0;
	for (unsigned i = 1; i < n; ++i)
	{
		penultimate += last;
		std::swap (last, penultimate);
	}
 
	return last;
}

This is the fastest of implementations offered here, with the exception of the memoizing one (and only in amortized sense.) But nothing prevents us from applying the memoization technique to an iterative implementation as well, albeit not in a general and automatic way. It might not be apparent or significant in such a simple sample, but for some class of problems, recursive solutions are usually easier to devise and understand, and therefore easier to get right. In any case, nothing is clear-cut when it comes to programming, and I'm almost offended when people (specially people who should know better) behave as if almost everything is.

VN:F [1.9.13_1145]
Rating: 8.0/10 (6 votes cast)
VN:F [1.9.13_1145]
Rating: +2 (from 4 votes)

There Should Be Dancing Around a Bonfire!

This should be no news to anybody who has anything to do with writing and distributing C/C++ applications on Windows, but Microsoft has finally decided to drop the fucking SxS shit for Visual C++ 2010 CRT and go back to the sweet old days of plain, distributed-alongside-your-application DLL files! (Read here if you don’t believe me! I don’t know how far one can trust MSDN and how long that link will stay valid (I mean, how hard is that?! Keep your stupid fucking links valid, you idiot douche bags!) but there it is for now, and I have verified it on VC2010 RTM.)

How fucking twisted is that?! I’m actually rejoicing because we are going back to DLL Hell! But after experiencing the abyss of WinSxS Hell, I would happily crawl back to the open and only mildly tormenting depths of the good old DLL Hell. This means that I will (hopefully!) never ever have to mess around with ass-busting manifests and colossally subtle version conflicts and hunting down every single gods-damned version of every single fucking-gods-damned CRT component that might or might not have been subject to some whimsical patch by the morons at Microsoft in the past year, in one or other version of Windows. This means that I will just distribute the fucking version of the CRT that seems to barely work alongside my applications (that is, in the same directory) and it will probably (say 30% instead of 1e-10%) work, and no one will be able to override their usage behind the poor hapless user’s back (using conventional methods; that is. Everybody knows how easy it is to hijack a function call into a DLL in Windows; which I have to say is not necessarily a bad thing.)

And don’t anyone dare ask me why I link to CRT as a DLL in the first place, instead of a statically linked LIB!

P.S. I have decided to write as I think (regarding the usage of curse words.) So no more fraks and friggins and butts and backsides. Deal with it.

VN:F [1.9.13_1145]
Rating: 8.3/10 (6 votes cast)
VN:F [1.9.13_1145]
Rating: +2 (from 4 votes)

A Lesson in “Test” Attitude

Back in the old days of the net, even before I was born, people did implement TCP/IP stacks. And since there weren’t much of a solid and standard specification (not to mentions decades of engineering experience in implementation and maintenance of network stacks,) these implementations tended to be buggy, unstable and non-conforming. To test these various TCP/IP implementations (such as they were,) people used to come together and just test them against each other and compare their functions. These sessions and discussions and reviews were called “TCP and IP bake offs”. It has been said that as a result of these discussions, the specifications were as likely to change as the implementations!

These dudes pretty much built the whole frakking Internet without the bureaucracy and the 3000-page conformance guidelines and the 2-million line test suit or the 12 years worth of committee meetings. Their procedures, and much more importantly their attitudes is quite concisely demonstrated in RFC 1025.

VN:F [1.9.13_1145]
Rating: 8.7/10 (9 votes cast)
VN:F [1.9.13_1145]
Rating: +4 (from 6 votes)

Fun with C++: new, delete and Some of the Rest of the Story

Every C++ programmer knows new and delete and how they work. At least it must be so. I sure as hell didn’t know all the theory and detail behind C++ memory management facilities until 3-4 years ago, and I’m obviously still learning the practical details. So, please bear with me and see if there are things that you can learn about these old pals of ours, new and delete.

First, we all should know that new and delete are C++ operators, with all their facilities (and shortcomings, of course.) But not exactly like other operators, you can override them at a global level for every type that does not provide its own type-specific such operators. These global operators are provided as part of the C++ runtime library and are easily overridden. Their declarations are:

1
2
3
4
5
6
7
// The single-object versions
void * operator new (size_t mem_size);
void operator delete (void * mem_block);
 
// The array versions
void * operator new[] (size_t mem_size);
void operator delete[] (void * mem_block);

What new does is allocate a block of memory, and then call the constructor for the type with the address of the newly allocated block passed in as the this pointer. A delete call does the reverse; calling the destructor and then de-allocating the memory. The difference between the single-object versions and the array versions is only in the number of c’tor/d’tors they call. It amazes me how many C++ programmers don’t know and don’t care about details such as this (if you are programming in C++, these kind of details can and will bite you in the places you don’t want to be bitten!) If you fail to match them correctly, they allocate and de-allocate the correct amount of memory for the array or the single object, they just might not call constructors and destructors for all the objects being allocated or freed. That’s it.

Also, there is that small detail about exception-handling handling (yeah, two “handling”s!) The new operators may only throw an object of a sub-type of std::bad_alloc and only in the event that the requested amount of memory cannot be allocated. delete operators should never throw any exceptions (just like destructors. Remember that!) So, the correcter declaration for these operators would be:

1
2
3
4
5
6
7
// The single-object versions
void * operator new (size_t mem_size) throw (std::bad_alloc);
void operator delete (void * mem_block) throw ();
 
// The array versions
void * operator new[] (size_t mem_size) throw (std::bad_alloc);
void operator delete[] (void * mem_block) throw ();

Again, it is amazing how many programmers either don’t know about function exception specification and exception safety or just don’t use them (that includes me.) Of course, compiler providers are at least a little to blame here too. For example, Microsoft C++ compiler only distinguishes the empty exception list after a function declaration (meaning it doesn’t throw anything.) Anything else put there, just is taken to mean the default behavior is used (i.e. this function does throw something sometimes.)
In the meantime, the relationship between C++ programmers and exception handling remains in the love/hate/ignorance/hate/apathy/hate stage.

Later on, I’m going to talk abut overloading these global operators for fun and profit. Stay tuned! ;)

Obviously, a related problem to memory management is calling the c’tor and d’tor for an object directly. Uses for this may not be immediately apparent, but as a few examples I could name implementing good smart pointers, memory pools, memory managers, garbage collectors, generic object containers (e.g. std::vector) and such.
You probably already know how to call the destructor on an instance directly. If you have a pointer x to an object of type T, you can call its d’tor like this: x->~T() (note that you should not generally call the d’tor in this way, unless you yourself have called the c’tor directly on that instance as well.) Calling the constructor is a bit trickier though (not really; I’m just being foreboding!)

What you should realize is that you can overload new and delete with different signatures that the ones above. You can add arguments and of different types. There are a few other signatures for these two provided by the standard C++ library (yeah, there are others!) The less interesting of them are:

8
9
10
11
12
void * operator new (size_t mem_size, std::nothrow_t const & please_dont) throw ();
void operator delete (void * mem_block, std::nothrow_t const & please_dont) throw();
 
void * operator new[] (size_t mem_size, const std::nothrow_t & please_dont) throw ();
void operator delete[] (void * mem_block, std::nothrow_t const & please_dont) throw();

Forget about the deletes for a minute. The additional parameters to the new calls above are actually not used inside of the functions. Any object of type std::nothrow_t will suffice as the second parameter; it will be there just to signal the compiler to use this particular overload of the operator, which doesn’t throw any exceptions whatsoever. I just need to emphasize again that the regular new never returns a NULL pointer. It just throws an exception. But this one returns a 0 pointer upon failure and never throws anything, being it rocks, shoes or exceptions. The syntax for calling them, as you might suspect, is peculiar:

13
14
15
16
17
18
19
20
21
#include <new>  // for std::nothrow
//...
T * p = new (std::nothrow) T (/* usual constructor parameters */);
// The line above calls a particular "new" overload with two
// parameters: a size_t and a std::nothrow_t.
// Oh, and std::nothrow is just an object of type std::nothrow_t.
//... 
delete p;
</new>

Notice that I didn’t call the delete with any extra parameters or anything. In fact, there is no syntax in C++ for calling delete with any parameters! Besides, delete is already a non-throwing function. So what gives?! Why is there a paired delete for every frakking new when there is no frakking way of calling them?! You should keep your cool. I may explain them (if you don’t already know,) or we can leave the subject as an exercise. I would just say that the paired delete is called by the code generated by the compiler in a very specific situation.

Note that anything other than the straightforward, unary new and delete is called a “placement new/delete“. However, I’ve heard the term be used for a specific overload, which is more interesting and looks like this:

21
22
23
24
25
void * operator new (size_t mem_size, void * mem_ptr) throw ();
void operator delete (void * mem_block, void * mem_ptr) throw ();
 
void * operator new[] (size_t mem_size, void * mem_ptr) throw ();
void operator delete[] (void * mem_block, void * mem_ptr) throw ();

The implementations for the above operators are really simple. Here’s a complete listing:

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
void * operator new (size_t mem_size, void * mem_ptr) throw ()
{
    return mem_ptr;
}
 
void operator delete (void * mem_block, void * mem_ptr) throw ()
{
}
 
void * operator new[] (size_t mem_size, void * mem_ptr) throw ()
{
    return mem_ptr;
}
 
void operator delete[] (void * mem_block, void * mem_ptr) throw ()
{
}

Note that although I haven’t written it, the constructor and destructor calls happen outside of my control. These versions of new and delete are used when we don’t want to allocate or free any memory, and just want the constructors and destructors to be called. For new, we just pass in a pointer to another sufficiently-sized memory location and ask the compiler to generate the code to call the c’tor upon that area of memory. That’s how we call a c’tor directly. We procure some memory area from somewhere and use that, like this:

43
44
45
T * x = (T *)malloc (10 * sizeof(T));
for (unsigned i = 0; i < 10; ++i)
    x[i] = new (x + i) T (/*usual c'tor params. */);

These standard placement operators cannot be hidden or overridden in user code, but there is still a ton of fun to be had.

You can very easily replace the old, simple and default operators with an implementation of yours, a la:

46
47
48
49
50
51
52
53
54
55
56
57
58
59
void * operator new (size_t mem_size)
{
    void * ret = malloc (mem_size);
    if (0 == ret)
        throw std::bad_alloc ();
    return ret;
}
 
void delete (void * mem_block)
{
    free (mem_block);
}
 
// the array versions are exactly the same

As I have stated earlier, the c'tor/d'tor calls are generated automatically for you by the compiler. So now you are free to write your own memory manager!

The way that memory manager/debugger/helper/whatevers usually work under the hood is that they allocate more memory than you have requested, and put their own junk right before and/or right after the area that gets passed back to the user (that's a bad way to do memory management, but that one is a long story.) Some of the stuff that are usually kept there include a pointer to the next and/or previous allocated block of memory (so all the blocks form a linked list,) sentinel values right before and right after the user area to detect buffer overruns (e.g. 0xdeadbabe,) the size of the memory block, the code file/line/function/module that allocated this particular block and so on and so forth. Actually, your default memory manager in the CRT is doing this right now. Just new two large-enough blocks of memory and compare their address differences with the size of the first block. The runtime accompanying some compilers (like VC++) even exposes their internal data structures and means to work with the memory manager (although rather passively.)

You need to keep in mind though, that what I have discussed so far barely scratches the surface of writing memory managers. These are just practicalities and implementation details; the state of the art on the theory of the matter and memory allocation algorithms, policies and mechanisms can fill several books. Even on the implementation side, there are really serious issues with performance, cache-friendliness, thread-safety, multiple thread support, etc. need taking care of.
Besides, much (if not most) of the memory (de)allocation going on in a C++ program these days go through C or operation system API, shared object files (DLLs,) through third part code or through STL, all of which bypass the basic technique discussed above. So, if you really are serious, you should investigate the existing memory debuggers or memory leak detectors or memory managers. There are several open source ones out there, with various degrees of sophistication and complexity. Have fun! (But for what it's worth, I should mention that we have used a memory leak detector using nothing but this technique in Garshasp and a similar project before, and in both projects it has been a great help.)

VN:F [1.9.13_1145]
Rating: 8.0/10 (11 votes cast)
VN:F [1.9.13_1145]
Rating: +3 (from 7 votes)

Time, Only Time

I have a post about measuring time in a game engine on the Grashasp Dev Blog. Give it a read if you have the time and you are interested.

VN:F [1.9.13_1145]
Rating: 7.0/10 (4 votes cast)
VN:F [1.9.13_1145]
Rating: -1 (from 1 vote)

Fun with C++: Function Try Blocks

C++ is complex. That might sound like an about right to two groups of people – those who don’t know C++ and those who really know C++ – but only those who really know understand the depth of that statement. I’m only beginning to learn C++ and I’m only just learning the depth of it.

Take the following sample code for instance:

1
2
3
4
5
6
void foo ()
try {
    // Some code
} catch (...) {
    // More code
}

As surprising as this might be to some (or not) the above is a valid C++ function definition. That’s right. No regular body in this function.
Now, the skeptics among you might wonder what usefulness this might possibly have! Wonder no longer. The foremost use (and the most straightforward one) is in the context of constructors and correct exception handling.

Suppose you have the following class and constructor:

1
2
3
4
5
6
7
8
9
10
11
12
struct Bar
{
    Bar ();
 
    // Baz is another class that might throw an exception in its c'tor.
    Baz m_baz;
};
 
Bar::Bar ()
    : m_baz ()
{
}

How can you handle exceptions that might be thrown when m_baz is being constructed (e.g to do something useful with them?)
The answer is obviously a try body for the constructor. A la:

1
2
3
4
5
6
7
Bar::Bar ()
try
    : m_baz ()  // Note the "interesting" placement!
{
} catch (std::exception & e) {
    std::cerr < < "'Bar' c'tor is FUBAR!" << std::endl;
}

This has other very cool usages too. For example, to define a macro, with an aesthetically pleasing usage, to track entry into any function (for run-time call graph generation and other analyses.)

1
2
3
4
5
6
7
8
9
10
11
12
#define TRACK_FN                                 \
    try {                                        \
        GlobalFunctionTracker::onFuctionEntry    \
            (__FUNCTION__, __FILE__, __LINE__);  \
        throw (42);                              \
    } catch (int)
 
// Use the above macro like this
void qux (int arg) TRACK_FN
{
    // Do your thang here...
}

Of course, this is not the most efficient way to implement this, but its the most beautiful one!
Some notes:

  1. In effect, we are injecting code into the scope of the function. All the function arguments are available in the try and catch blocks.
  2. If you use this try-block thingy for a constructor or destructor, the exceptions thrown in the try block will propagate automatically beyond the local catch! For all other kinds of functions, this will not happen and if you catch the exception, it will be stifled unless you rethrow it explicitly.
VN:F [1.9.13_1145]
Rating: 10.0/10 (2 votes cast)
VN:F [1.9.13_1145]
Rating: 0 (from 0 votes)

Fun with C++: Singletons

I just realized that I’ve not posted anything technical in a long while. Here’s my effort to remedy the situation.
This is a modified version of the straightforward implementation of the “singleton” pattern (STFW yourself.)

Let me add this. I’m rather proud of this code, so I ask you please to give this code a read if you are even a little interested.

First the definition of the singleton (which I named Zingleton to be used in Zorvan) and the handle class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
//==========================================================
 
#include <cassert>
 
//==========================================================
 
#define DEF_ZINGLETON(T)  \
        template<> T * Zingleton<t>::ms_theone = NULL; \
        template<> int Zingleton</t><t>::ms_refcount = 0
 
//==========================================================
 
template <typename T>
class ZingletonHandle
{
public :
  inline ZingletonHandle ();
  inline ~ZingletonHandle ();
 
  inline T const * operator -> () const {return m_ptr;}
  inline T * operator -> () {return m_ptr;}
 
  inline T const & operator * () const {return *m_ptr;}
  inline T & operator * () {return *m_ptr;}
 
protected :
  T * m_ptr;
};
 
//==========================================================
 
template </typename><typename T>
class Zingleton
{
  friend class ZingletonHandle<t>;
 
public :
  static ZingletonHandle</t><t> getZingleton ()
  {
    return ZingletonHandle</t><t>();
  }
 
protected :
  Zingleton ()
  {
    assert ((NULL == ms_theone && ms_refcount == 0) ||
	        (NULL != ms_theone && ms_refcount > 0));
    assert ((NULL == ms_theone && ms_refcount == 0));
 
    ms_theone = static_cast</t><t *>(this);
    ms_refcount = 1;
  }
 
  ~Zingleton ()
  {
    --ms_refcount;
 
    if (ms_refcount < = 0)
    {
      ms_theone = NULL;
      ms_refcount = 0;
    }
  }
 
private :
  static T * zingletonAcquire ()
  {
    if (NULL == ms_theone)
    {
      assert (0 == ms_refcount);
      zingletonCreate ();
    }
 
    assert (ms_refcount >= 0);
    ++ms_refcount;
 
    return ms_theone;
  }
 
  static void zingletonRelease (T const * instance)
  {
    assert (instance == ms_theone);
    if (instance != ms_theone)
      return;
 
    assert (NULL != ms_theone);
 
    --ms_refcount;
    assert (ms_refcount >= 0);
 
    if (ms_refcount < = 0)
      zingletonDestroy ();
  }
 
  static void zingletonCreate ()
  {
    assert (NULL == ms_theone);
    if (NULL == ms_theone)
    {
      ms_theone = new T ();
      ms_refcount = 0;
    }
  }
 
  static void zingletonDestroy ()
  {
    if (NULL == ms_theone)
      return;
 
    assert (0 == ms_refcount);
    delete ms_theone;
    ms_refcount = 0;
  }
 
protected :
  static T * ms_theone;
  static int ms_refcount;
};
 
//==========================================================
 
template<typename T>
inline ZingletonHandle</t><t>::ZingletonHandle ()
  : m_ptr (Zingleton</t><t>::zingletonAcquire())
{
  assert (NULL != m_ptr);
}
 
//----------------------------------------------------------
 
template<typename T>
inline ZingletonHandle<t>::~ZingletonHandle ()
{
  assert (NULL != m_ptr);
  Zingleton</t><t>::zingletonRelease (m_ptr);
}
 
//==========================================================
</t></typename></t></typename></t></cassert>

I think the code is clear enough, so I’m not gonna explain it any more! Let me just say that the handle class is there as a specific kind of smart pointer.
Here’s one way to use it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
//==========================================================
 
#include <iostream>
 
//==========================================================
 
// Either include or paste the above code snippet here.
 
//==========================================================
 
class TestZ : Zingleton<testz>  // "CRTP"? Say what?
{
public :
  TestZ () {cout < < "+It's alive!" << endl;}
  ~TestZ () {cout << "+I'm dying here..." << endl;}
 
  void Print () {cout << "+Hello, world." << endl;}
};
 
//----------------------------------------------------------
 
DEF_ZINGLETON (TestZ);
 
//==========================================================
 
void use_zingleton ()
{
  cout << "-Start of use_zingleton()..." << endl;
 
  ZingletonHandle<TestZ> h;
  h->Print ();
 
  cout < < "-End of use_zingleton()." << endl;
}
 
//----------------------------------------------------------
 
int main ()
{
  cout << "-Start of main()..." << endl;
 
  {
    cout << "-Entered inner scope..." << endl;
 
    ZingletonHandle<TestZ> h;
    h->Print ();
 
    use_zingleton ();
 
    cout < < "-End of inner scope." << endl;
  }
 
  cout << "-End of main()." << endl;
  return 0;
}
 
//==========================================================

When (if) you run the above code, it should produce something like this:

1
2
3
4
5
6
7
8
9
10
-Start of main()...
-Entered inner scope...
+It's alive!
+Hello, world.
-Start of use_zingleton()...
+Hello, world.
-End of use_zingleton().
-End of inner scope.
+I'm dying here...
-End of main().

As you can see, only one instance of the TestZ class is created and it is destroyed only after all the handles are destroyed. Basically, the handles are objects that guarantee that the singleton is alive and valid in their lifetime.

Homework: There is at least one very serious bug in the above code (that I’m unaware of.) What is it? It’s not the thread-safety issues because I’m aware of that and may fix and post again (that’s a great opportunity to talk about policy-based design in C++, so it demands another post or two.

VN:F [1.9.13_1145]
Rating: 10.0/10 (7 votes cast)
VN:F [1.9.13_1145]
Rating: 0 (from 0 votes)

Of Boost and Men

Boost is a great collection of libraries. The functionality is so diverse and the quality is so high and the design is so careful that it’s almost part of the standard C++ library (of course, many of Boost’s sub-libraries has already been accepted for inclusion into the next version of C++ standard library with little or no modification, and more are scheduled for discussion.)
People who develop Boost are fantastic software designers and all C++ gurus. I consider myself a seasoned C++ programmer and I can’t honestly say that I can follow their discussions without extensive reference look up and pondering (the times that I know what they are talking about, that is!) This has led to both Boost’s greatest strengths and weaknesses.
Obviously, when you have many great developers and well-defined, open and democratic processes, you’re gonna get good FOSS. It also leads to a perceived elitism and high entry barrier. From the “outside”, it looks like Boosters all want to keep the glory to themselves, and that they would shoot down any library submitted for inclusion by an “outsider.” I’ve not been around the Boost discussion lists long enough and I haven’t been paying a close enough attention to know this for sure, but it seems to me like most people there are volunteers, more interested in quality and advancement for their (and my) beloved language, rather than glory-seeking adventurers after fame and fortune.
Also at first glance, Boost might seem like a bag of cryptic and hard-to-learn libraries, shrouded in mystery and magic. It is not quite like that, but given the fact that C++ is a difficult language (yeah, your hunches in your freshman year were right, if not the reasons behind them) you should expect some complexity is some of its (arguably) most advanced libraries.

If nothing else, use Boost’s thread, filesystem, serialization and async I/O libraries. The thread library is pretty much already a part of standard C++ anyway, so you might as well learn to use it (not that it is hard to use.) Lack of portable file system access has always been a weakness on C and C++. The serialization library is so unintrusive and fantastic, that it will find its way and place in any non-trivial program that we’ll ever write. And asio has so much needed functionality, that I’m just itching to try it out.
And when you are already using one part of Boost, why stop there? Use anything and everything you can. Not blindly, of course, but prefer well-designed, well-developed and well-tested libraries to some small code snippet you find off the web. And when using Boost, delve into it and see how it is implemented. It’s educational and more often that not even enlightening for the likes of me.

VN:F [1.9.13_1145]
Rating: 8.2/10 (5 votes cast)
VN:F [1.9.13_1145]
Rating: 0 (from 0 votes)

Boost 1.36.0 is Out

Shame on me! Boost 1.36.0 got released and I didn’t even know it was coming this soon. It’s been several weeks that I haven’t read the mailing list. Think of all the C++ goodness I’ve lost!
I’ll get it off the SVN (if my ISP let’s me; damned idiots) and build it in a few hours, and I’ll try to upload it.

VN:F [1.9.13_1145]
Rating: 7.8/10 (4 votes cast)
VN:F [1.9.13_1145]
Rating: 0 (from 0 votes)

Fun with C++: Useless Consts?

Many C++ programmers see the keyword “const” as something redundant that only gets in the way. They curse Stroustrup and his ancestors each time they encounter a const-related compile error because of that view and fail to use it correctly quite often (note that I’m not saying that I’m not one of these people, but I curse neither Stroustrup nor anyone else.)

If you ask them about the purpose of the const keyword, they would give you the classic answer that any C++ textbook gives: variables declared as consts cannot be changed by the programmer, and const class methods cannot modify their instance data (and can be called on const class instances), etc.

The programmer may give you the textbook answer (or some mutilated version of it, depending on which textbook she read and how much of it she actually remembers,) but she is wondering with herself who will stop the other programmer to change the header file and remove the const from the declaration? Who is there to prevent her from doing so?!

She may even make a conjecture that if she removes all the consts from all her source files and headers (including standard and 3rd party headers she uses,) then her programs will continue to compile and work just fine (after all, the const keyword has no runtime effect. It’s an exclusively compile-time construct, is it not? So if her programs used to work, and they compile after removing all consts, they should continue to run without problem.)

If she is a little bit more sophisticated and skilled in C++, she knows that the C++ compilers differentiates between functions that take const arguments and those that take exactly the same arguments, but not const. This fact lets you have function overloads that only differ in constness of their arguments. The same is also true for template specializations (which is a form of overload anyway.)

So this more sophisticated C++ programmer will conjecture that if she removes all the consts and eliminates the redundant overloads (which were nothing but nuisances to begin with) then her programs will compile.

Now, is she right? Is this the case with const?
(I should say that I know of one case that is not so (the program will not compile without the the const) but it’s not a common case. I’ll write about that in a later post (if no one guesses it first.) I’m genuinely interested in other such cases.)
(Another note. The use of const frees the compiler to do some optimizations that may not be safe with a non-const object. My question is about correctness and not about performance.)

VN:F [1.9.13_1145]
Rating: 8.2/10 (5 votes cast)
VN:F [1.9.13_1145]
Rating: 0 (from 0 votes)

Fun with C++: When Parentheses Don’t Call!

Just a quick one. Most of us have come to think of parentheses as sometimes necessary but always harmless little creatures. Our view is that unless parentheses change the order of evaluation (and therefore the meaning) of an expression, they are completely harmless.
Well, while that is true almost by definition, there are cases that we might not realize the meaning of an expression is being changed. One such case is in the presence of the versatile and extremely useful (and possibly massively pain inducing) comma operator (‘,‘.)
You see, the comma has two uses in C++ language: as an operator and as a separator for many different lists of things in the language grammar (function arguments, object declaration, etc.) In the first context, a pair of parentheses work exactly as anyone would expect; in the second, probably not. The problem is that the use of commas in the first context is not common at all, while the commas of second kind riddle any and every C++ source file. It’s mixing the meaning of the uses that’ll lead to potentially cryptic compile errors (what a shocker! Cryptic compile error messages in C++?!), or worse, logical bugs that will make you wish you were coding in machine language.

Just for the sake of comprehensiveness, while I know that you all know how the comma operator operates, I’m gonna describe its workings anyway. The comma operator has the lowest precedence among all the operators in C++ and it is a left-associative operator (meaning “a, b, c” will be evaluated as “(a, b), c“.)
An expression of the form “a, b” (where a and b are expressions themselves (and not statements)) will always evaluate a first, and then b and will return the evaluated value of b.
Please believe me when I say that overloading this operator can achieve magic and convenience one can only dream of in C++! Just see the Boost.Assignment library for a sample.

One place that the implicit mixing up of the meaning of comma could cause trouble is in function calls. Suppose that a function X accepts two arguments. Now, if instead of X (a, b) someone writes X ((a, b)) then they will be given a compile error saying that function X does not take one argument(s);-) . This is because the extra pair of parens have changed the meaning of the comma from a simple argument list separator to a C++ operator.
This will not confuse any C++ programmer out of her first few months with the language, and will be obvious and easy to find and fix. But what if the extra pair of parentheses is the result of a macro expansion? Then you’ll have to chase down the macro definition. Still not very hard, because the compiler will catch you. But what happens if the X function has an overload with a single argument, incidentally with a type compatible with b? What happens if the function takes more than two arguments and has many overloads and it’s called like this: X (a, (b, c), d, (e, f, g))?
I should probably list this as another macro pitfall. Take care where you put parentheses! Don’t just slap them whenever you’re in doubt!

VN:F [1.9.13_1145]
Rating: 8.2/10 (5 votes cast)
VN:F [1.9.13_1145]
Rating: 0 (from 0 votes)