Rules for Effective C++
Recently, however, my views have changed after reading Scott Meyer's book, Effective C++. In Meyer's book, he goes through every feature of C++ and shows you how you have to program with extreme care to avoid undefined behaviour. It seems like every modern feature that C++ has was specifically designed to help you shoot yourself in the foot.
I never realized this before, because I simply never use these dangerous features. In this article, I'll show you how to program in C++ safely.
What you may not know is that using exceptions in C++ makes a lot of code unsafe. In effect, it means
that you cannot use pointers. Take this code, for example:
If you are a C++ programmer and you use exceptions, you should see the obvious memory leak. If bar()
throws an exception, or calls any function that throws an exception, then obj will not be deleted.
It's actually quite hard to induce these functions to fail, so even if you did handle their failure, you probably wouldn't test it. Do you really want to be releasing code that you haven't tested? There are cases where it would be better for your program to crash, then to continue to operate in an undefined state.
However, there are times where I would check whether a memory allocation failed:
C++'s Broken Exceptions
Take exceptions, for example. Many programmers will tell you that they are a great idea. They let you
indicate errors when creating object, and avoid making you check return codes. You can handle errors in
the areas of the code that is prepared to handle them.
void foo()
{
MyObject* obj = new MyObject();
bar();
delete obj;
}
Steve's rules for effective C++
I have been programming in C++ for a decade, and I never realized these flaws until I read Meyer's
books. I find C++ to be just fine, and the reason for that is because I program in a style that doesn't
involve these pitfals. Here's how you can program in this way too:
Avoid exceptions
Exceptions will only leave you open to the memory and resource leaks. Don't use them. The exception to this rule is if you are programming in a style that doesn't use pointers, and everything is encapsulated into smart pointers.
Constructors should do nothing
Constructors have no way of returning an error code (unless you use exceptions, which are bad). That means that your constructors shouldn't do any real work. Don't try to open up a database connection, or call any functions that could fail.
Constructors should be used only to initialize data members.
Use copy constructors sparingly
Copy constructors are very error prone, because they are another thing that you have to remember to change if you add a data member. You're much better off if you don't allow copying at all. Just pass pointers around. If you must pass by value, then don't put anything in your object, like pointers, that will require special handling. That way, you can use the automatically generated copy constructor. Unlike you, the compiler will never forget anything.
Use malloc or new without checking the result
I used to write programs that checked every call to malloc() and new() for failure. In Microsoft C++, the new() operator will actually through an exception if it fails, so checking for NULL is useless anyway. Today's machines have gigabyes of memory, and you don't need to verify every call to malloc() or new().
When you are programming for an embedded device, however, it might be beneficial to not check the return code of malloc. This is when there should be enough memory in the heap for all operations. If your process silently fails when memory allocation fails, you might never catch a memory leak that is exhausting your heap. It is much better to fail catastrophically by trying to use the NULL pointer than silently failing.

Comments