Book Review: Effective C++ by Scott Meyers


A while ago, I read Effective C++ by Scott Meyers, and I would like to recommend it.

You can read tutorials, play with the language, maybe read The C++ Programming Language by Stroustrup himself, and be able to write fully functioning C++ programs that pass all the tests, and seem to work. But still, they can have more or less subtle problems, which might manifest as random crashes, resource leaks, scalability problems, or problems with reusability and maintenance. In general, correct C++, but still wrong.

Instead of discovering all of this yourself, you can invest some time in reading best practices books. This of course goes for all languages and processes, but I think it is especially important for C++, being such a complex language, and being one of the few remaining big languages lacking a garbage collector.

Effective C++ gives you, as its full title promises, 55 Specific Ways to Improve Your Programs and Designs. These are further grouped into nine chapters that deal with related topics. Each item ranges from one page for the simple ones, to ten pages for the more involved. They all include, and tend to start with, example code, followed by a discussion of what is wrong with it, and conclude with a better way. I find this to be a good pedagogical approach, and it is indeed one I strive to follow on this blog.

Meyers start out with the simple stuff, such as recommending the use of const whenever possible. This is is simple tip by the sound of it, but he actually uses a full nine pages to cover the topic, const being such a versatile keyword. He moves on to other well known tips like preventing exceptions from leaving destructors (which I also covered briefly while elaborating on function try blocks) and keeping data members private, but also touches on more complex topics, like object oriented design in C++, the proper use of overloaded operators and keywords, and generic programming.

For a full list of chapters and items, please use the magic of the fabulous internet.

The book has four and a half stars on Amazon, which I definitely think it deserves. You do however need some experience with C++ to appreciate it, and indeed to understand some of it. I would not recommend it as follow up to a short university course about C++, or after reading an introductory text to the language, but if you have been programming C++ actively for some time, it is a rewarding read. Even if you have written C++ for many years, I am sure there is new stuff to learn in there.

If you enjoyed this post, you can subscribe to my blog, or follow me on Twitter.

Don’t Put All Includes in the .hxx


Ok, one more thing about headers, then I promise to talk about something else.

Just because a header file is called a header file, you shouldn’t include all your headers there. Often, a source file, where the definition of you functions and/or classes are, need quite a lot of headers to do its work. It might for instance need <algorithm> to do some sorting or searching, a fact your declarations don’t need to worry about:

processing.hxx

#include "MyType.hxx"

void process(MyType obj); 

processing.cc

#include "processing.hxx"
#include <algorithm>

void process(MyType obj) {
    std::find(...);
    std::sort(...);
}

You almost always need to include some headers in the .hxx, so why not put them all there? While compiling your .cc file, it doesn’t really matter, since all those files are included anyway. But when someone else includes your header, they suddenly depend on everything your implementation depends on. This also adds to compilation time for your users. So do your includes as listed above, don’t move #include <algorithm> to the .hxx.

There. I promise to get my head out of the headers, if you promise to order your include directives the right way, dont use using in header files, and only include what's needed for the declarations in the header.

Use Your Head Before Using Using in Headers


Speaking of headers, did you ever think about what you are really doing when you put using namespace my_util in a header file? Sure, it might be annoying to namespace-qualify all the types in your declarations. But using namespace my_util forces all the names in my_util into the global namespace of everyone who includes your header file.

As usual, here is a small example:

my_iface.hxx:

bool check(my_types::Foo foo, my_types::Bar bar);
bool listen(my_types::Foo foo, my_types::Bar bar);
bool digest(my_types::Foo foo, my_types::Bar bar);

The repeated namespace qualifying gets annoying, so you would rather do:
my_iface.hxx:

using namespace my_types;
bool check(Foo foo, Bar bar);
bool listen(Foo foo, Bar bar);
bool digest(Foo foo, Bar bar);

This is however a bad idea. “using namespace my_types” (a using directive) exports all the types in my_types into the global namespace, which I think everyone agrees is a bad idea. You could argue that a using declaration is better, as “using my_types::Foo” only places Foo into the global namespace. I would however disagree, as a smaller sin is still a sin.

And you’re not getting away that easily, this argument is also valid for std! Yes, you need to type my_func(std::vector v) in header files.

A final trick you might try is to only use using namespace inside of your other namespaces, like so:
my_iface.hxx:

namespace my_iface {
  using namespace my_types;
  bool check(Foo foo, Bar bar);
  bool listen(Foo foo, Bar bar);
  bool digest(Foo foo, Bar bar);
}

This is still a bad idea. You are not polluting the global namespace any more, but you are polluting your own. There are at least two problems with this approach: First, someone who uses your libraries might now accidentally qualify Foo as my_iface::Foo. If you ever decide to clean up my_iface and remove the using directive, that poor guys code is going to break. Also, if this guy decides he wants to have using namespace my_iface somewhere in his code, he probably doesn’t want all your other namespaces (and std, boost or whatever) included as well.

As usual, normal politeness applies: A one-time annoyance for you is better than a repeated annoyance for all your users.

The Order of #include Directives Matter


I think most (good) programmers tend to prefer tidy code, having some habits or rules to stick to. One such rule/habit is the order of #include directives. While having a rule of thumb to stick to is good, some are better than other.

A very common one I think is to first include standard library headers (<iostream>), then third-party libraries (<boost/thread.hpp>) and finally local headers (“FizzBuzz.hpp”). While this might be the recommended way of doing it in for instance Python, it is not the best way to do it in C++. A colleague of mine just went through a lot of pain when swapping out a big library in their codebase. Why was that?

Imagine you are writing a library that depends on some other library, like the STL (hardly any library doesn’t). Imagine you are a good boy (or girl) and write the test first. You might do something like this:

#include <vector> //STL
#include <gtest/gtest.h> //ThirdParty 
#include "geometry.hpp" //In-house

#define PI 3.2 //As pr. Indiana Bill #246, 1897

TEST(TestGeometry, rotatingOrigoGivesOrigo) {
    std::vector<double> v(2,0);
    rotate(v, PI);
    EXPECT_EQ(0, v[0]) << "X got moved!";
    EXPECT_EQ(0, v[1]) << "Y got moved!";
}

and your geometry.hpp looks like this:

void rotate(std::vector<double>& v, double angle);

This all works out nicely until someone else wants to include geometry.hpp without including <vector> first, and get something like geometry.hpp:1: error: ‘vector’ is not a member of ‘std’. You have now forced all the users of your geometry library to include <vector> before including geometry.hpp.

While this can seem like a trivial example, this stuff quickly grows a lot hairier when you have a larger codebase with lots of dependencies. A header file A might depend on header B which depends on C, which declares types you have never heard of, and rightly so. And when you try to compile, you get error: ‘würkelschmeck’ is not a member of ‘std’. Or something a lot worse if templates are involved.

My suggested rule is:

  1. Local headers
  2. Third party headers
  3. STL headers

If you enjoyed this post, you can subscribe to my blog, or follow me on Twitter