Welcome to MSDN Blogs Sign in | Join | Help
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.

Posted: Wednesday, October 18, 2006 7:40 PM by cashto

Comments

Brooks Moses said:

Interesting -- though I think it's important to point out that most of those things on your list are things that you don't have to learn from the STL, and this depends a lot on your background.

For instance, I came to C++ from modern Fortran and so the whole idea about strings being copied on assignment, and local-variables being deconstructed when they go out of scope, and returning objects from functions, and so forth -- all of that was pretty much what I expected.  After learning all the effort that Fortran goes through to make dynamically-allocated arrays "just work" in all those situations, it seemed obvious to me that that was what should happen.

On the other hand, I get tripped up in the places where these ideas don't work.  Object polymorphism, for instance, pretty much seems to require explicit pointers and copy constructors and explicit dynamic casts somewhere, even if they're buried deep in the internals of a wrapper class.  It took me quite a while to figure out how all of that ought to work, and to get comfortable with it; I'm still working on that.

# November 13, 2006 6:56 PM

Anony Moose said:

Object polymorphisism requires indirection. In C++ this means either "pointers" or "references".

e.g.

class Base { ... };

void myfunc( const Base &obj ) { ...use Base's methods (virtual or otherwise) here... }

class Derived : public Base { ... };

void caller()

{

   Derived myobj;

   myfunc( myobj );

}

No "new" or "delete" and definately no wrapper classes or casting, but the author of myfunc() doesn't need to know anything about class Derived, and virtual methods will have the appropriate classes implementation executed.

Still, dynamic memory allocation plus smart pointers are good things, but object lifetime management is separate from polymorphisim. It's just that books rarely teach the concepts separately.

And in fact it is still possible to learn all that without knowing the STL, but knowing the STL correctly implies knowing these things, and you can read very little modern C++ code without at least having a vague ability to understand the basics of the STL.

# November 13, 2006 9:39 PM

cashto said:

Yeah, I too am puzzled by the references to "copy ctors", "explicit dynamic casts" and "wrapper classes" in relation to polymorphism.  If polymorphism didn't exist, the only alternative would be switch-on-type-field and dynamic cast to a subtype -- in that sense, the goal of polymorphism is to get rid of dynamic casting.  A cast here and there is sometimes necessary, but if you do it with any regularity then I suspect you're doing polymorphism all wrong.

I came to C++ after learning only Basic, C, and Java.  Only in Basic was string a value type -- I understood what "a$=b$" did, but Basic wasn't a "real language" to me, and anyways string handling was special-cased by the language -- in OO versions of Basic like VB, objects have reference semantics.  Strings are the oddball.  In Java (and C# for that matter), all objects (strings included) have reference semantics.  And C is its own ball of wax.  So yeah, it shocked me to see value semantics in C++, and that it could even be extended to composite types and containers like vector and list.  I didn't have the benefit you did of seeing it first in FORTRAN.

Likewise I loved ArrayList in Java, but didn't know of anything similar in C++, until I met std::vector.  

Agreed that knowing the STL isn't the only route to understanding value semantics, but for C++ programmers it's the most common route, and it correlates strongly with "knowing STL".

# November 14, 2006 1:19 AM

dan said:

dude, I think you just didn't know C++ period, just how to use classes

# November 14, 2006 2:27 AM

George Sudarkoff said:

Allow me to assure you that you still don't get C++. STL is _not_ about containers that automagically expand if needed. It's about things you can do with those containers. Generically!

But that's a good start! Keep digging.

# November 14, 2006 3:48 AM

cashto said:

Yep, you're right.  I didn't know how to use anything else in C++ except classes.  

That's the point of the whole article, after all.

The misconceptions I had about C++ are by no means rare.  The scary thing is, my ignorance didn't stop me from writing C++.  I was able to churn out plenty of working C++ programs (although it usually took me twice the lines of code that it should have).  So I thought I "knew C++".

Now that with the benefit of hindsight, I see the error of my ways.  That's why knowledge of the STL is my "C++ knowledge" litmus test, and it's why if someone asks me if it's necessary to know the STL to be a C++ programmer, I point them to this article.

# November 14, 2006 3:51 AM

cashto said:

To George: I'm pretty aware of STL algorithms and have been to use map, accumulate, and find_if on occasion.  sort is the poster child of STL algorithms, but apart from that one I'm not nearly as impressed with them as I am with the whole "hey, an expanding array!" bit.  Learning about the containers dropped my LOC count by half OVERNIGHT.  Algorithms, not so much.

And as far as the syntax of standard as well as custom-defined functors ... let's just say, C++ is not well-suited for writing lambda functions (yes, I know Boost has improved this somewhat, but it's still not as nice as other languages).

Algorithms ... eh, I could give them a miss.  Feel free to enlightmen me if you think otherwise.

# November 14, 2006 3:59 AM

Liam Clarke said:

Thanks for the article! I started programming in Python, and dabbled in C a bit, but based on my experiences there, didn't move onto C++.

But after reading your article, I realised "Wow. C++ has classes like Python had."

Yes, ignorant, but no longer. :)

# November 14, 2006 6:27 AM

Ricky Clarkson said:

"In Java (and C# for that matter), all objects (strings included) have reference semantics"

In Java, object references are passed by value.  That's not the same as being passed by reference.  Changing the value of a parameter doesn't affect the calling method.  You can't implement a public void swap(String a,String b) any more than you can implement a swap(int a,int b).

# November 14, 2006 6:30 AM

Dave said:

Geaorge is right, it sounds like you've just scratched the surface of the STL. It's worth studying. Once you realise how to use its features (especially iterators and function objects) and how elegantly they all plug together, it will totally change the way you write and *think* about C++ code.

# November 14, 2006 10:06 AM

cashto said:

"In Java, object references are passed by value.  That's not the same as being passed by reference."

Uh, yes it is.  

"Changing the value of a parameter doesn't affect the calling method.  You can't implement a public void swap(String a,String b) any more than you can implement a swap(int a,int b)."

But you *can* implement a swap(Point, Point) function.  Chew on that for a sec ...

The only reason why you can't write a swap function for Strings is that Strings are immutable -- i.e., there's no "setChar" or "setValue" function for String.  If you want to change a string, you have to throw it out and construct a new one.

But most classes are mutable.  Point is a simple example, but countless others exists.  Most of the time you CAN change an object, and when you do, it will affect the same object the caller passed in.  If you're unaware of this, it can lead to subtle bugs -- which is also one of the reasons why String was designed to be immutable, to reduce confusion on this point.  See http://www-128.ibm.com/developerworks/java/library/j-jtp06243.html for more information.

# November 14, 2006 1:13 PM

Monkeyget said:

I'm afraid you're wrong and Ricky Clarkson is right. There is a difference between passing an the reference of an object by value and passing an object by reference.

Taking the example of swap :

String s1 = "aaaa"

String s2 = "bbbb"

swap(s1, s2)

swap(String a,String b){...}

-When you do "object references are passed by value" (The only way it can be done in java and the default way in C#)

pointer to s1 and s2 are COPIED to give a and b.

If you do inside swap "a = b" it won't affect the caller because you changed the copy of the pointer (the pointer a is changed but not the pointer s1).

Therefore its indeed impossible to perform the swap.

-When you do "pass object by reference" (which can be done in C# by doing "Swap(ref String a,ref String b)"

pointers to s1 and s2 are passed to the swap function. No copy done. Therefore when you change what a and b point to, you also change what s1 and s2 point to! That's the crucial difference.

If you do inside of the swap method( the one with the ref keyword) "a = b". a will now point to the object pointed by b AND s1 will be changed too!!

Therefore, with "pass by reference" you can implement a swap function without touching the content of the objects, you just swap the pointers!

For more info see : http://javadude.com/articles/passbyvalue.htm

( "Can you write a traditional swap(a,b) method/function in the language?" should be "Can you write a traditional swap(a,b) method/function in the language if a and b are immutables?"

It's the kind of stuff that's really easy to grok when explained visually on a blackboard.

# February 22, 2007 11:29 AM

cashto said:

Really we're talking about three things: pass by value, which is what C++ does if you don't use the funky ampersand (&).  The entire object gets copied via operator=.

The second is what you call passing object references by value, and I shorten to "passing objects by reference".  No copies of any objects are made, simply pointers to the underlying objects.  In C++, you can't implement swap if the objects are immutable (i.e., swap(const foo&, const foo&)).  But we call it pass by reference.

The third thing is something I'd call "passing object references by reference".  In C++, you can't have references to references, but you can think of it as having a reference to a pointer.

There's no confusion, it's just a difference of terminology -- which arises largely from the fact that in C++, there is a distinction between an object and an object reference, and in Java, there isn't.

# February 22, 2007 5:29 PM

Emery said:

I recommend that you read some of Bjarne Stroustrup's own publications to really understand C++. The true power is in generic programming.

As Stroustrup says: C++ is an experts language. I've been using it almost every day of my life for the last 8 years or so, and I still discover new things on almost a weekly basis.

I've always been able to look a year into the past and notice that I knew so much less than I thought I did. I have no idea when this constant discovery will reach its limits. C++0x should be finalized and adopted by then, and we'll all have more to master.

# April 15, 2007 9:14 PM

IvyMike said:

This is a little bit of a nonsequitor, but I predict that eight years from now, you'll be saying "If you don't know boost, you don't know C++".  Just boost::shared_ptr alone changes everything.

# June 5, 2007 5:41 PM

Joel said:

Do you know how shocked I am at the things that shocked you?  

You NOT only didn't know C++, you were clueless about C, in fact, you probably should go back to take all your CS classes all over, especially courses related to Programming Language and computer architecture.  Also, "Know STL" does NOT mean you understand the C++ concepts that make STL possible.  You could be using the classes from STL to write a C++ program and you are still clueless about C++ and computer languages.  

# February 14, 2008 1:12 PM

Joel said:

Know STL doesn't mean you know C++, know C++ doesn't mean you need to know STL.  

Know C++ doesn't mean you are using it as its designer intended.  Its designer said it best here:  http://www.research.att.com/~bs/new_learning.pdf

# February 14, 2008 1:43 PM

Bryan said:

Shame. I see you're getting slammed for being honest.  Bless the Internet where everyone is an expert.  I appreciate your article and honesty though.

What you describe is so common for many programmers who learned C++ in the mid-1990s, though I doubt many are too ashamed to admit it. When I first learned C++ there was no STL and you just had classes with the C libraries.  If you programmed C++ on Windows it was the same--making calls to Win32 C API functions or using the MFC framework.  I think when most programmers heard of the STL, they flocked to adopt stl:string and stl:vector, but beyond that, Win32 or MFC provided what C++ programmers on Windows wanted to use.

Lately though I think C++ education and the C++ community is improving.  We're seeing a move away from platform-centric libraries towards a standard set of libraries such as STL and Boost.  We even have open-source libraries like Qt that allow very easy GUI development with C++.  Sure you have to get deep into Win32 or POSIX sometimes, but there are libraries that take care of a lot of the work now.

I also would add that the beginner texts have significantly improved and focus on platform agnostic C++ that utilizes the STL from the start.  There are even good intermediate books like "Effective C++", "C++ Common Knowledge" and "C++ Cookbook".  

# September 16, 2008 10:39 PM

Johnathan said:

I really like this post, it helps me understand things about the language. My question would be what the most important things to know in the STL are. Is that even a valid question, or is it like asking what the most important letter in the alphabet is? Just food for thought, thanks for writing this

# February 18, 2009 2:04 AM
Leave a Comment

(required) 

(required) 

(optional)

(required) 

  
Enter Code Here: Required

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Page view tracker