Chapter 17. Conclusion

Now that we’ve reached the end of this book, let’s go back and summarize the guidelines and strategies we’ve discussed. The first guideline is that we want to diagnose as many errors at compile time as possible. All the other errors will be diagnosed at runtime, and most of the strategies in this book concentrate on catching these errors.

When catching errors at runtime, we are trying to achieve two contrasting goals:

  • Testing as many sanity checks as possible.

  • Having our code run as fast as possible in production.

This can be achieved by making some of the sanity checks temporary. To do this, you need to enable your checks to be switched on and off at compile time and activate them for testing only.

Here is a summary of all the rules formulated in this book.

For diagnosing errors at compile time (Chapter 2):

  • Prohibit implicit type conversions: declare constructors taking one parameter with the explicit keyword and avoid conversion operators.

  • Use different classes for different data types.

  • Do not use enums to create int constants; use them to create new types.

To avoid an “index out of bounds” error (Chapter 4):

  • Do not use static or dynamically allocated arrays; use a template array or vector instead.

  • Do not use brackets on the new and delete operators; leave allocation of multiple elements to the template vector.

  • Use scpp:vector instead of std::vector, and scpp::array instead of a static array. Switch the sanity checks on.

  • For a two-dimensional array, use the scpp::matrix class (or similar classes for higher-dimension arrays) with operator () providing indexes-out-of-bounds checks.

To avoid errors in pointer arithmetic (Chapter 5):

  • Avoid using pointer arithmetic at all. Use a template vector or array with an index instead.

To avoid errors with invalid pointers, references, and iterators (Chapter 6):

  • Do not hold pointers, references, or iterators to the element of a container after you’ve modified the container.

To avoid uninitialized variables, especially data members of a class (Chapter 7):

  • Do not use built-in types such as int, unsigned, double, bool, etc., for class data members; instead use Int, Unsigned, Double, Bool, etc. You will not need to initialize them in constructors.

  • If you use these classes instead of built-in types for passing parameters to functions, you get additional type safety.

To avoid memory leaks (Chapter 8):

  • Every time you create an object using the new operator, immediately assign the result to a smart pointer (a reference counting pointer or scoped pointer is recommended).

  • Use the new operator only without brackets. If you need to create an array, create a new template vector, which is a single object.

  • Avoid circular references.

  • When writing a function that returns a pointer, return a corresponding smart pointer instead of a raw one, to enforce the ownership of the result.

To catch dereferencing a NULL pointer at runtime (Chapter 9):

  • If you have a pointer that owns the object it points to, use a smart pointer (a reference-counting pointer or scoped pointer).

  • When you have a raw pointer T* that points to an object you do not own, use the template class Ptr<T> instead.

  • For a const pointer (e.g., const T*) use Ptr<const T>.

To avoid errors in copy-constructors and assignment operators (Chapter 10):

  • Whenever possible, avoid writing copy constructor and assignment operators for your classes.

  • If the default versions created for you automatically by the compiler do not work for you, consider prohibiting copying instances of your class by declaring the copy constructor and assignment operator private.

To avoid problems when throwing exceptions from constructors (Chapter 11):

  • Design your class in such a way that the destructor is empty.

To avoid errors when writing comparison operators (Chapter 12):

  • Write a CompareTo() function and use the SCPP_DEFINE_COMPARISON_OPERATORS macro to implement all six comparison operators for your class.

To avoid errors when calling C-library functions such as buffer overflows and crashes caused by NULL pointers (Chapter 13):

  • Avoid using C string libraries; use the string and ostringstream C++ classes instead.

The best possible testing mode is to compile code in debug mode with all sanity checks activated. In this mode, all runtime errors will lead to calls to the same error handler function where you can wait with a debug breakpoint. The code will run until a sanity check fails, at which time you will have an opportunity to debug the code that leads to the failure.

The next best mode is slightly faster: running tests when code is compiled in release mode with sanity checks on and relying on the completeness of the error messages to diagnose the errors. This mode might be necessary if the code compiled in debug mode with sanity checks on is too slow. You might even want to leave some of the sanity checks on in production if you think they might be triggered. For this reason, I’ve made writing these sanity checks as easy as possible, so you can write as many of them as you need and make them informative enough to diagnose the error without the use of a debugger.

Finally, when your tests pass all your sanity checks, you have good reason to believe that your program is working correctly. And the more sanity checks you’ve put in there, the more reason you have to believe this is true.

If you follow all the rules in this book, you will essentially be using a “safer” subset of C++ that should lower the “bug count” in your code. Of course, this book covers only the most common errors one can make when programming in C++, so even if you do follow all the rules, there is still lots of opportunity for mistakes. Therefore, instead of being titled Safe C++, this book could have been more realistically called Safer C++. Of course, completely safe C++ (or any other language) is an unattainable dream, but I hope that avoiding the errors discussed in this book brings us one step closer to this goal.

The strategy discussed in this book looks very simple. That’s because it is. The whole idea of this book can be summarized as follows: design your code to be self-diagnosing. This strategy makes testing faster, easier, less stressful, and more productive; it relies on the compiler and runtime code to catch your errors, it speeds up development, makes testing much less stressful and more productive, and at the end of the day makes your code more reliable. Go ahead and apply it to your next project—I think you’ll agree with me that it works!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.143.247.125