The C language provides a macro, called assert, that is used to verify conditions that must be true at any point of the program. These include preconditions, postconditions and invariants, all of which are explained in introductory programming courses. Whenever an assertion is violated, the program is abruptly stopped because there is most likely a bug in its code.

C++, like C, also provides the assert macro in the cassert standard header. However, there is another way to verify program sanity without using it. How? Using exceptions.

The std::logic_error exception is provided with this situation in mind: to verify that a certain condition holds true at a specific point of the program. If it does not, the program logic (hence the name) is incorrect and must be fixed. Using this method has some advantages, but also some disadvantages. Let's see them.

Using an exception, you can provide a descriptive error message of what failed. The assert macro only prints out the assertion triggered, which causes difficulties to decipher what really made the assertion false. Using an exception, you can add more information, such as the value of an specific parameter (in the case of a precondition) to let the developer know what's wrong.

Furthermore, when you catch one of these exceptions (you'd usually do that from your program's main function with a global try/catch block), you can tell the user that something went wrong, where to report the bug, what information to include, etc. In other words: you can decide how the program will end, instead of simply getting an abort trap.

However, there are some drawbacks in this approach too. The first one is that you'll have to manually create some macros to verify an assertion and throw the correct exception. This is to allow you to quickly disable all of them when building production code; otherwise you'd slow down your program quite a bit (it may not matter at all depending on the nature of your program).

But, maybe, the most important problem you can encounter is that you cannot use this method from within destroyers, as explained here. It may sound strange, but a destroyer can rightfully expect some preconditions to be true.

The method you use is up to you: it can be one of these two or a custom one you write (such as global functions used as logic error handlers). But, whichever it is, add assertions to your code.