Pseudo Associative

Random thoughts on software development

7 notes

Weakness of STL over plain C types

One of the joys of working with Google’s Go programming language is that it is kind of like writing C/C++ but without the extreme verbosity of C++. For various reasons I have used pure C lately, and just as with Go I get struck by how much less verbose your code ends up being. Okay to be fair, C is fairly primitive. A lot of stuff requires you to pretty much give up type safety completely.

But I believe C++ is going down the wrong path. I was sold on STL, boost etc for a long time until I realized I was never going to get used to the overly verbose code it leads to. They tell you it will just become natural, but it doesn’t. It becomes unreadable. Syntax gets in the way of meaning and your colleagues can’t read your code. Debugging it is even worse. Try debugging the code below or more complicated. Stepping through it and making sense of what is going on quickly becomes a bitch.

list<int> L;
...
list<int>::iterator first_nonnegative =
find_if(L.begin(), L.end(), bind2nd(greater_equal<int>(), 0));

We are told the right way to iterate through an array is this.

vector<int> a(size);
a[0] = 1;
a[1] = 2;

for (vector<int>::const_iterator i = a.begin(); i != a.end(); ++i) {
cout << *i << endl;
}

But consider how much less verbose and readable the equivalent code is in C.

int a[size] = {1, 2};

for (int *p = a; p != a + size; ++p) {
printf("%d\n", *p);
}

But we put up with this because C++ and STL gives us dynamic arrays, safer memory handling etc. Which brings me to the next point. One of the key points STL is to avoid loads of code duplication using collections.

Recently I found myself needing to write code like this.

GetResult(buffer);

I wanted to keep the options open with respect to how the memory for buffer was allocated. I might had to allocate many small buffers frequently, hence the possible need for alternative memory allocation.

void GetResult(vector<int>::iterator out);

The normal solution in C++, looks something like what you see above. But that only allows be to pass the iterator of a container allocated in the standard fashion.

void GetResult(vector<int, single_client_alloc>::iterator out);

If I wanted to use another allocation scheme for the buffer I want to fill up, I have to change the type of the iterator as shown above. Only now I have limited my function to only work with iterators pointing to buffers allocated with the single_client_alloc allocator.

int a[10];
int *b = malloc(10*sizeof(int));
int *c = custom_allocation(10);

GetResult(a);
GetResult(b);
GetResult(c);

With plain old C types this problem does not exist. A pointer does not care about how the memory it points to was allocated.

void GetResult(int *buffer);

This works for all the cases above. With the added benefit that it is a lot less verbose and more readable.

Undoubtedly C++ solved many problems of C, but it created so many new problems of its own that it is now always obvious is we have gained that much.

I feel like one of those who have been standing admiring the emperors new clothes without realizing he is naked. Everyone important has said he is wearing clothes, just as everybody important has told we need to use STL containers, iterators, algorithms etc. When the novice C++ programmer could see all along that using regular arrays, indices or pointers is often easier.

  1. assoc posted this