Uses assert () in bad C ++ practice?

I usually add a lot of assertions to my C ++ code to simplify debugging without affecting release performance. assert is now a pure C macro, created without using C ++ mechanisms.

C ++, on the other hand, defines std::logic_error , which should be thrown in cases where there is an error in the program logic (hence the name). Throwing an instance might just be the perfect, more alternative C ++ version for assert .

The problem is that assert and abort both terminate the program immediately without calling destructors, so they skip cleaning, while throwing an exception manually adds unnecessary runtime overhead. One way to create your own SAFE_ASSERT confirmation SAFE_ASSERT , which works the same as a C copy, but throws an exception on error.

I can provide three opinions on this issue:

  • Adhere to statement C. Since the program terminates immediately, it does not matter if the changes are deployed correctly. Also, using #define in C ++ is just as bad.
  • Throw an exception and catch it in main (). Providing code to skip destructors in any state of the program is bad practice and should be avoided at all costs, as well as terminate () calls. If exceptions are thrown, they must be caught.
  • Throw an exception and end it. The exception ending with the program is fine, and because of NDEBUG this will never happen in the release build. The trap is not needed and provides implementation details for the main() internal code.

Is there a definitive answer to this problem? Any professional link?

Edited: Skipping destructors is, of course, undefined behavior.

+76
c ++ coding-style assert
Aug 21 '12 at 20:15
source share
5 answers

Statements are fully suitable for C ++ code. Exceptions and other error handling mechanisms are not really intended for claims.

Error handling is when it is possible to correctly repair or report a problem to the user. For example, if there is an error while trying to read the input file, you can do something about it. Errors can occur due to errors, but they can also be just the appropriate output for a given input.

Claims are for things like checking API compliance, when the API is not usually checked, or to verify that the developer believes that he guarantees the construction. For example, if an algorithm requires sorted input, you would usually not check for this, but you might have a statement to test it so that debugging creates a flag for such an error. The statement always indicates an incorrectly running program.




If you are writing a program where an unclean shutdown can cause a problem, you can avoid claims. Undefined behavior strictly in terms of the C ++ language cannot be regarded as a problem here, since the assertion is probably already the result of Undefined behavior or violation of some other requirement that could prevent some cleaning from the correct operation.

Also, if you implement statements in terms of exclusion, you can potentially catch and handle it, even if it contradicts the very purpose of the statement.

+62
Aug 21 '12 at 20:18
source share
  • Statements are for debugging purposes. The user of your submitted code should never see them. If the claim has been removed, your code must be fixed.

  • Exceptions for exceptional circumstances. If someone meets, the user will not be able to do what he wants, but can return to another place.

  • Error handling is a regular program flow. For example, if you ask the user for a number and get something irreparable, this is normal, because user input is not under your control, and you should always handle all possible situations for granted. (For example, loop until you have a valid input, followed by "Sorry, try again.")

+87
Aug 21 '12 at 20:21
source share

Do not run destructors due to alling abort () is not undefined behavior!

If that were the case, it would be undefined behavior to call std::terminate() as well, and what's the point of providing it?

assert() just as useful in C ++ as it is in C. Claims are not for error handling, but for immediately canceling a program.

+12
Aug 21 '12 at 20:35
source share

Statements can be used to check internal implementation invariants, such as the internal state before or after the execution of a method, etc. If the statement fails, it really means that the program logic is broken, and you cannot recover from it. In this case, the best thing you can do is break down as soon as possible without passing an exception to the user. What is really nice about assertions (at least on Linux) is that the main dump is generated as a result of the completion of the process, and so you can easily examine the stack trace and variables. This is much more useful for understanding a logical failure than an exception message.

+12
Aug 21 '12 at 20:35
source share

IMHO, statements are intended to test conditions that, if they are violated, make everything else meaningless. And therefore, you cannot recover from them, or rather recovery does not matter.

I would group them into two categories:

  • Developer sin (e.g., a probability function that returns negative values):

float probability () {return -1.0; }

assert (probability ()> 0.0)

  • The machine is broken (for example, the machine that runs your program is very wrong):

int x = 1;

assert (x> 0);

These are trivial examples, but not too far from reality. For example, think of naive algorithms that return negative indices for use with vectors. Or firmware in custom hardware. Rather, because shit happens.

And if there are such errors in development, you should not be sure that any mechanism for recovering or processing errors is implemented. The same goes for hardware errors.

+4
Dec 16 '14 at 18:37
source share



All Articles