News:

This week IPhone 15 Pro winner is karn
You can be too a winner! Become the top poster of the week and win valuable prizes.  More details are You are not allowed to view links. Register or Login 

Main Menu

C++ tips - Prefer compile-time and link-time errors to runtime errors

Started by ben2ong2, October 07, 2006, 03:58:51 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

ben2ong2

(This example taken from "Effective C++" by Scott Meyers, p. 175-178.)


As defined in the ARM ..., there is no such thing as a mandatory runtime
error in C++. No detection of division by zero, no checking for array bounds
violations, nothing of that kind. Once your program gets through the compiler
and linker, you're on your own -- there's no safety net. ...

Whenever you can, push the detection of an error back from runtime to
link-time, or, ideally, to compile-time.

Such a methodology pays dividends not only in terms of program size and
speed, but also in terms of reliability. If your program gets through the
compiler and linker without eliciting any error messages, you know that
there aren't any compiler- or linker-detectable errors in your program,
period. (The other possibility, or course, is that there are bugs in your
compiler...).

With runtime errors, the situation is very different... You can test your
program till you're blue in the face, but you'll still never cover all the
possibilities...

Often by making relatively minor changes to your design, you can catch
during compilation what might otherwise be a runtime error. This frequently
involves the addition of new types to the program. For example, suppose that
you are writing a class to represent dates in time. Your first cut might
look like this:

   class Date {
   public:
      Date (short day, short month, long year);
      ...
   };

[a better approach would be]

   enum Month { Jan, Feb, Mar, ..., Nov, Dec };

   class Date {
   public:
      Date (short day, Month month, long year);
      ...
   };

Unfortunately, this doesn't buy you that much, because enums don't have to
be initialized:

   Month m;
   Date d (22, m, 1857);    // m is undefined

As a result the date constructor would still have to validate the value of
the month parameter.

To achieve enough security to dispense with runtime checks, you've got to
use a class to represent months, and you must ensure that only valid months
are created:

   class Date {
     public:
   
      class Month {
        friend class Date;

        private:
         const unsigned short monthNumber;
         Month (short number) : monthNumber(number) {}
      };

      Date (short day, Month month, long year);

      static const Month Jan, Feb, ..., Nov, Dec;
   };

   const Date::Month Date::Jan(1);
   const Date::Month Date::Feb(2);
   ...
   const Date::Month Date::Dec(12);

... Because the Month objects are statics inside Date, a date must be
declared like this:

   Date d (22, Date::Apr, 1857); // month name is fully qualified

This is ugly, but this ugliness can be hidden by the clever use of global
references...

   const Date::Month& Jan = Date::Jan;
   const Date::Month& Feb = Date::Feb;
   ...
   const Date::Month& Dec = Date::Dec;
You are not allowed to view links. Register or Login
You are not allowed to view links. Register or Login