If you don't know the STL, you don't know C++
I'm ashamed to admit it now, but for about eight years of my professional career, I went around saying that I knew C++, when I really had no clue.
In my defense, I wasn't exactly lying -- "lying" implies intentional deception when one knows the truth all along. Truth is, I didn't know what I didn't know. I thought I knew C++ -- turns out, I was just programming in C, with occasional sprinklings of the class and virtual keywords.
But I didn't really "get it" until a couple years ago.
You may have heard that C++ is a language which allows you to define data types that act just like native types. I certainly did. I saw that ubiquitous complex number class example, where operator+ and operator* were redefined to do the right thing. Steve Yegge sums up my response: "Wow. He's right. It is useful".
Then I forgot all about it and went back to programming in very C-like C++.
Before I get too much into it, I should explain what's wrong with C. The problem with C is that it's a very low-level language. It's been described before as "portable assembly language", which is absolutely correct. Now sure, some people LIKE having that level of power. To be honest, I do too sometimes. But most of the time I'd rather cut down trees with a dull butter knife than to program at that level of detail.
In particular, C is missing one important feature that every other language has built in: the ability to model a 1:n relationship, where n has no fixed upper bound. In C, the only you tool you have is a fixed-sized array, and that's it. Every other language has lists or arraylists built into the language. Heck, in any other language strings are basic types, and after all, a string is just an ordered collection of characters.
And so, in C, if you want to deal with strings of arbitrary length, linked lists, or any other 1:n relationship, you've signed yourself up to write reams of code to allocate, copy, and free structures and to resize arrays. And you've got to be so careful that when you add a new field to a structure, that all this boilerplate code is correctly written. It's extremely tedious.
Which gets me back to the point about being able to define data types in C++ that act just like built in types. Up until I saw this line of code, I really had no clue the limits of what's possible:
std::string s2 = s1;
When I saw this, I was shocked that I could subsequently modify s1 without concern about s2, because strings had value semantics (aka copy semantics), not reference semantics. It worked just like integers ... if I assigned i2 to i1 and then changed i1, there's no reason why i2 should change. If you told me the same could be true for strings, I would just stare at you like you grew antennae on your head, because I couldn't possibly think of strings as ANYTHING ELSE but pointers to fixed-sized arrays of char.
No one ever explained it to me quite like that, which is why I went around eight years doing it all wrong.
There was a whole host of things I didn't know about C++ before I learned the STL:
- I didn't know destructors were called automatically when local variables go out of scope. I thought they only happened when you deleted a pointer to a new'd up object.
- I didn't know C++ automatically generates copy constructors and assignment operators for you, if you don't define them yourself. Not only that, it does the right thing. If you define a "Contact" class with a string for a name, and a vector<string> as a list of email addresses, "Contact c1 = c2" makes a copy of everything.
- I didn't know that C++ automatically calls the destructors for the member variables of a class at the end of the containing class's destructor.
- I didn't know you could return objects from a function. I thought you could only returns native types, or pointers, nothing else.
- When I learned about exceptions, I thought you always had to write reams of cleanup code in the catch clause. I didn't know about RAII.
- I didn't realize just how useful templates were. I always thought they were nigh-useless: I couldn't imagine myself ever writing a template class. I still can't, actually. But no one ever pointed out the utility of using a small set of vital, standard template classes like vector, list and string.
In short, I didn't understand how THE WHOLE LANGUAGE conspires to do the right thing, if only you'd stop thinking of it as a glorified C. It's actually quite elegant, in its own way.
These days, I can write a several-thousand line application and not use the delete keyword once, nor use a single pointer in the entire codebase. Considering that pointers and manual memory management are the two most bug-ridden features of C, I consider that a huge accomplishment. I estimate that I write about half the lines of code that I used to.
These days, I consider "do you know the STL?" as a litmus test for whether someone knows C++. Some have said to me that this is unfair, that the STL is "just a library". Wrong. It is the library. I would no sooner hire a C programmer that never heard of printf than I would hire a C++ programmer that never heard of std::vector. I'm not asking that they memorize all of printf's specification flags, or be able to give a stirring rendition of what bind2nd is and why you'd ever want to use it -- but there's a certain level of basic knowledge that a C++ programmer absolutely must have.