Why assert macro makes use only for debug build - c++

Why is this a common practice to have assert macro do something useful only in debug configuration? If it exists to test invariants and detect coding bugs, then would not it be easier to go ahead and do the same big boom in production software?
I have some S60 background and there exist __ASSERT_ALWAYS and __ASSERT_DEBUG, where the latter is equivalent to assert.

Asserts are made for stuff that should never happen, i.e. if it does then there is a bug in your code that you need to fix. Releases are builds that are "supposed" to be bug free, and killing application with the assert for the user is as bad as any other faulty behavior.

Checking for assertion costs. You have extra operations that you may not want to exist in the final product. If assertions were always going to work, then people would start using them less "to not kill performance". And believe me, there are a lot of people out there who consider the extra checks a performance kill and would avoid it. These are the same people who actually have to use assert more!
A more important reason is that, assert, if failed, will just abort your program. There is no usefulness in that whatsoever for the end user (except perhaps for security, to avoid running code with unexpected data, but that's arguably better handled by actual error checking). If you want your program to actually terminate with a message or do something useful, you would have to write your own assert. In that case, you can of course choose to keep it in release mode also.
Finally, assertion helps you find bugs, especially hidden bugs, but in the execution of the software, they may actually not happen. Imagine the following code:
struct X
{
// other stuff
int stage;
};
X x;
... do some stuff
assert(x.stage == STAGE_2);
x.stage = STAGE_3; // go to next stage
... do more stuff
In such an example, your logic says x should be in STAGE_2. If it is not, it's a bug. However, if you remove the assert, fix x.stage and move on, there is hope that the bug is not so severe. In such a case, the end-user can actually continue working without noticing this. If you had kept assert in release mode too, you would force the application to exit over a bug that didn't have any visible effect.
In reality, you get updates all the times for your software, in which they claim they have fixed bugs. Some of those, are indeed bugs that assert would have caught. However, you as the end-user didn't have any problem and were actually happy that you weren't interrupted due to those asserts, weren't you?

I think it's a cultural thing. The arguments in favour removing this kind of check in production code go like this:
It makes your code run slower.
It makes the final executable larger.
Your code shouldn't have bugs in once it ships.
It will cause your program to exit suddenly and violently, with possible loss of data.
The arguments against run as follows
You're shipping the exact code that you tested.
Debugging problems reported in the field gets much easier
Regardless of what you'd like to think, the code you ship WILL have bugs
Performance and size effects are typically minimal.
Failing fast may be preferable to attempting to continue when your program is in an undesired state.
Personally, I ship software that's built exactly as it's tested, asserts and all. But, a lot depends on your customer base and how you hope to schedule releases...
This article is worth a read:- http://www.martinfowler.com/ieeeSoftware/failFast.pdf
but what about when you deploy the software to customers? We don’t
want the application to crash just because there’s a typo in a
configuration file. One reaction to this fear is to disable assertions
in the field.
Don’t do that! Remember, an error that occurs at the
customer’s site made it through your testing process. You’ll probably
have trouble reproducing it. These errors are the hardest to find, and
a well-placed assertion explaining the problem could save you days of
effort.
One other thing - in C++, using BOOST_ASSERT you can set it to throw an exception on assertion failure, which makes handling and potentially recovering from assertion failures even more useful. we use this in conjunction with MadExcept so that any assert failures in the field can be easily posted by the user into our bug tracker, with complete call stacks, screenshots, whathaveyou.

assert works unless you explicitly turn it off. There's (usually) no
reason to turn it off, even in "release" builds, and most of the
released code I've delivered has had assert active.
The main reason for turning it off is performance. In this case, you
turn it off very locally, in the function where the performance is
critical, with something like:
#ifdef TURNOFFCRITICALASSERTS
#define NDEBUG
#include <assert.h>
#endif
// Function with critical code here...
#undef NDEBUG
#include <assert.h>
This is the way the C standards committee designed assert to be used.
Generally, you should not define NDEBUG except locally, like this.

Related

Should I add exception-handling to existing code base?

I'd like to know the advantages and disadvantages of adding exception-handling to existing code.
I work on a SDK that controls h/w cards in a Windows environment.
The SDK is made of more than 100 DLLs that interact with each other. Our existing code base probably contains 100 000s (if not 1 000 000s) of lines of code. Our modules are also heavily multi-threaded.
We link with the proper library so that we use nothrow new (lic.lib instead of licp.lib).
Most of the code doesn't have exception handling. The code is written with that in mind.
int *p = new int[size];
if (p == NULL)
{
// handle this case...
// most probably return an error code
}
char *q = new char[size];
if (q == NULL)
{
delete[] p;
// handle this case...
// most probably return an error code
}
We also use the RAII technique. For instance, we have a object created on the stack that automatically waits on and releases a critical section.
We want to improve the stability of our SDK. We were thinking of adding exception handling but I'm not convinced that it is the right way to improve the stability. I have to admit that I don't have much experience with EH.
The code, in general, checks for divide by 0 or checks for NULL pointers before dereferencing it. But, it still happens that such a case will happen. Since divide by zero or dereferencing a NULL pointer don't throw an exception, I am wondering how much useful is it to go thru 100 000s of lines of code and add exception handling which will change the workflow and may cause memory leaks if not handled properly. I experimented with SEH but I don't think it makes sense to start using SEH and it is Microsoft specific, isn't it?.
In my mind, I think that if it would be more useful to review the existing code and simply check for possible crashes such as divide by zero that may have been missed.
Also, if I were to add exception-handling, how would I proceed? Modify all the modules at once or start from the bottom-up (meaning, if Module A calls Module B which calls Module C, I would modify C, then B then A since we release our software quite frequently and we would probably only have time to modify C before the next release).
Thank you!
I'd like to know the advantages and disadvantages of adding exception-handling to existing code.
You don't say what you mean precisely by "exception handling", so I'll start with something fundamental: standard C++ (you tagged the question as c++) requires you to write code that "handles exceptions", for all but trivial applications, otherwise your code is faulty. Various parts of the C++ standard library are permitted to throw exceptions, including the new that your sample code uses. Therefore your code is already likely to have the possibility that exceptions could be thrown within it, which it must "handle". What happens in that case? Basically, you must write "exception safe code".
It is an error for a program to leak resources in the face of exceptions. You use RAII so you should be OK.
It is an error for any object to enter an inconsistent state after an exception is throw. Ensuring that can be much more tricky.
You should first focus on making your code exception safe.
With Legacy code, you should introduce exception handling in a few places as schedule permits; either the least accessed areas of the code (to reduce the risk of errors to the rest of the code base) or to where they would produce the most benefit (citical error places).
I do not recommend stalling a legacy project just to add exception handling everywhere. The hardest part about legacy code is to modify it and keep it working. After all, its been tested and its behavior is well documented.
I agree with Raedwald that if you are using C++ without a very careful coding standard to avoid EH (ex: using nothrow new, avoiding standard containers, etc), which I'm assuming the legacy code did not, then the code is already broken and is likely to leak and do sporadic things already in the face of exceptions it can already encounter like bad_alloc or bad_cast if you rely on dynamic_cast.
That said, from a very pragmatic standpoint with a legacy codebase, chances are that the legacy code managed to get away with it. And after all, how many non-trivial applications can gracefully recover from bad_alloc exceptions without very explicit control over memory allocation? Not many, and it doesn't cause the entire world to come to a screeching halt.
So I actually don't recommend rewriting the legacy code to try to catch exceptions and use RAII everywhere. You might utilize RAII here and there in code you absolutely have to modify, but I'd try to look for reasons not to change it too much. Write tests for it and try to stabilize it and turn it into a black box; a library of functionality to be used, not maintained and changed while wading through endless LOC indefinitely.
Now the main reason I pitched in here and resurrected this old thread (apologies!) is because of this comment:
The code, in general, checks for divide by 0 or checks for NULL
pointers before dereferencing it. But, it still happens that such a
case will happen. Since divide by zero or dereferencing a NULL pointer
don't throw an exception [...]
In my strong opinion, you should not throw in response to things like null pointer access or divide by zero because those are programmer errors. Unless you're working in a mission-critical software where you want to gracefully recover even if the software is buggy in order to try to reduce the risk of costing lives or something like that, you don't want the application to gracefully recover in the event of programming mistakes. The reason you generally don't want to do that is because it has the downside of hiding bugs, making them silent, allowing users to ignore and work around them and maybe not even bother reporting them.
Instead for programmer mistakes you should generally favor assert which doesn't involve exceptions at all. If the assertion fails, the software in a debug build will come to a halt and typically display an error message telling you where the assertion failed down to the precise line of code. That is usually the quickest bet to detecting and fixing these programming mistakes when running a debugger in response to a bug report, so feel free to assert liberally.
Exceptions are most useful for external exceptional events outside of a programmer's control. An example would be reading a file that turns out to be corrupt. That's not within the programmer's control to handle so there it's appropriate to throw and recover. Another example is failing to connect to a server, a user jamming an abort button for an operation that is supposed to finish, etc. Those are exceptional external input events, not programmer mistakes.
The best way to recover from programmer mistakes like null pointer accesses and divide by zeros is to first detect them (assert is handy), write a test to reproduce it, fix it and get the test to pass, and call it a day, not throw exceptions and catch them while leaving those mistakes in there.

Where to put Assertions?

Having assertions for unexpected conditions is considered to be good defensive coding practice. I happen to place assertions whenever i think something unexpected may happen, but that now seems to be an overkill to me.
Additionally, sometimes mild unexpected conditions that don't necessarily lead to crash may even cause failure on customer end.
Is there a hard and fast rule to put assertions?
Thanks.
The main difference between when to use assertions and exceptions:
Use an assertion to catch programming errors. Assertions should never happen if the code has been written correctly.
Use exceptions to catch run-time errors caused by unexpected environment.
If your program reads a script or contents from a file and they do not match the expected format, I consider that is a runtime condition therefore an exception.
You may decide, for debugging purposes, to use an assertion in the place where an exception is thrown simply to be able to work out more easily where it got thrown, although you can use exception macros that insert FILE and LINE into the message to do that too.
Where to put assertions?
What is often overlooked is that an assert can also serve as a documentation aid.
So don't only test for the 'unexpected', also use them to express your assumptions (invariants) at critical points in your code. Like assert(high >= low)
And of course make them conditional, as others have pointed out here.
No there is not... but I would definitely recommend treating assertions differently in test and production.
It is perfectly okay, in a test environment, to produce a core dump. It allows easy inspection of the conditions that triggered the assertion by nicely safe keeping the whole state of the program.
However in a production environment, you never want to crash (except in case of memory corruption...). The user is expecting the system to always respond, there is nothing more irritating that requesting something and never receiving a response. Therefore it is your job to ensure that the user gets the more meaningful response possible, even if it is an error message. The simplest way to achieve this is usually to throw an exception.
Assertions are put when you are very sure that some conditions have to be true before going to the next level of your code. For example when a window handle is invalid or when some varible is not having a valid value.
from the sounds of it, you leave them enabled in release builds. if so, create levels of assertions - those that will be enabled or disabled in certain builds. then just use an assertion level.
this way, you don't need to turn them down, off, or remove them for development and debug builds or beta releases.
i typically disable them in release, but they do consume a ton of written code. i don't think it's bad - it serves as documentation and enforces the interface to be used as intended. i think it's good to have what many devs may consider too many assertions, but there really aren't too many in the big picture because codebases evolve and this ensures that the programs are always used as intended. therefore, i don't recommend removing them, just disable the non-fatal checks for release builds.
ultimately, there are better approaches than levels (see discussion below and take what you want from others' responses) - but levels are one simple way to introduce the change without affecting existing programs considerably. this would be a good approach for a transition to another error handling scheme, or if you're >98% happy with what you have already.

When should assert() be used?

In developing a large C++ programming project with many developers, we have run into issues with inappropriate use of assert() in the code which results in poor quality where the assertion does indeed occur and the product crashes.
The question is what are good principles to apply to use assert() appropriately? When is it proper to use an assert() and when is it not? Is there a list of criteria that each assertion should pass in order to be legitimate? How can we encourage proper use of assert()?
As a first crack at this, I would say that assert() should only be used to document a condition that is believed to be impossible to reach and which should be identified as an assert() failure at run time where it ever to arise because programming assumptions are being violated.
Can folks do better than this? What is your experience with assert()?
Use Exceptions for error condition which come from the outside (outside the method or outside the program) like parameter checking and missing/defective external ressources like files or connections or user input.
Use Assertions to indicate an internal defects like programming errors, conditions that shouldn't occur, e.g. class/method invariants and invalid program state.
You should use assert to check all conditions that should never happen:
Preconditions on input parameters
Results of intermediate calculations
Postconditions on object state
But you should include those asserts only in debug builds or when explicitly activated for release (not in builds released to the customers).
I use asserts to check for any unwanted program state:
Function preconditions
Sometimes I insert them in a macro after every API call: glDrawArray(); checkOpenGLError();--checkOpenGLError() will call getGLError() if turned on
Data structure integrity: assert(something == null);
Sometimes GDB lies to me (iOS SDK 3.2). I use asserts to prove it.
Note that "unwanted program state" excludes errors that naturally occur at runtime, such as being unable to open a user-selected file due to permissions or HD failure. In these cases it is not wise to use assertions.
Much code nowadays has a lot of external dependencies and connections. I don't tend to use traditional assertions much these days, I favor exceptions. I don't feel like I can assume "this can never happen" and the checks can safely be removed in a non-debug build.

Are assertions always bad? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
I used to work for a company where some of the lead architect/developers had mandated on various projects that assertions were not to be used, and they would routinely be removed from code and replaced with exceptions.
I feel they are extremely important in writing correct code. Can anyone suggest how such a mandate could be justified? If so, what's wrong with assertions?
We use a modified version of assert, as per JaredPar's comment, that acts like a contract. This version is compiled into the release code so there is a small size overhead, but disabled unless a diagnostics switch is set, such that performance overhead is minimized. Our assert handler in this instance can be set to disabled, silent mode (e.g. log to file), or noisy mode (e.g. display on screen with abort / ignore, where abort throws an exception).
We used automated regression testing as part of our pre-release testing, and asserts are hugely important here as they allow us to find potential internal errors that cannot be picked up at a GUI level, and may not be initially fatal at a user level. With automation, we can run the tests both with and without diagnostics, with little overhead other than the execution time, so we can also determine if the asserts are having any other side effects.
One thing to be careful of with asserts is side effects. For example, you might see something like assert(MyDatabasesIsOk()), which inadvertently corrects errors in the database. This is a bug, as asserts should never change the state of the running application.
The only really negative thing I can say about assertions is they don't run in retail code. In our team we tend to avoid assertions because of this. Instead we use contracts, which are assertions that run in both retail and debug.
The only time we use assertions now is if one of the following are true.
The assertion code has a noticable performance impact
The particular condition is not fatal
Occasionally there is a piece of code that may or may not be dead. We will add an assertion that essentially says "how did you get here." Not firing does not mean the code is indeed dead but if QA emails me and says "what does this assertion mean," we now have a repro to get to a particular piece of code (it's immediately documented of course).
assertions and exceptions are used for two different things.
Assertions are used for states that should never happen. For example, a signalton pointer should never be null and this error should be picked up during development using an assert. Handling it with an exception is alot more work for nothing.
On the other hand exceptions are used for rare states that could happen in the normal running of an application. For example using fopen and it returns a null pointer. It could happen but most times it will return a valid pointer.
Using assertions is nether wrong nor right but it comes down to personal preference as at the end of the day it is a tool to make programing easier and can be replaced by other tools.
It depends on the criticality of your system: assertions are a failfast strategy, while exceptions can be used when the system can perform some kind of recovery.
For instance, I won't use assertions in a banking application or a telecommunication system : I'd throw an exception, that will be catched upper in the call stack. There, resources can be cleaned, and the next call/transaction can be processed ; only one will be lost.
Assertions are an excellent thing, but not to be confused with parameter/return value checking. You use them in situations that you don't believe will occur, not in situations that you expect could occur.
My favourite place to use them is in code blocks that really shouldn't be reached - such as a default case in switch-statement over an enum that has a case for every possible enum value.
It's relatively common that you might extend the enum with new values, but don't update all switch-statements involving the enum, you'll want to know that as soon as possible. Failing hard and fast is the best you can wish for in such circumstances.
Granted, in those places you usually want something that breaks in production builds as well. But the principle of abort()ing under such conditions is highly recommended. A good stack trace in the debugger gives you the information to fix your bug faster than guessing around.
Is it true that an assertion exists in the debug build, but not in the release build?
If you want to verify/assert something, don't you want to do that in the release build as well as in the debug build?
The only guess is that because an exception is often non-fatal that it makes for a codebase that does not die in some odd state. The counter-point is that the fatality of an assertions points right to where the problem is, thus easy to debug.
Personally I prefer to take the risk of an assertion as I feel that it leads to more predictable code that is easier to debug.
Assertions can be left on simply by not defining NDEBUG, so that's not really an issue.
The real problem is that assertions call abort(), which instantly stops the program. This can cause problems if there is critical cleanup your program must do before it quits. Exceptions have the advantage that destructors are properly called, even if the exception is never caught.
As a result, in a case where cleanup really matters, exceptions are more appropriate. Otherwise, assertions are just fine.
We use assertions to document assumptions.
We ensure in code review that no application logic is performed in the asserts, so it is quite safe to turn them off just shortly before release.
One reason to veto assert() is that it's possible to write code that works correctly when NDEBUG is defined, but fails when NDEBUG is not defined. Or vice versa.
It's a trap that good programmers shouldn't fall into very often, but sometimes the causes can be very subtle. For example, the code in the assert() might nudge memory assignments or code positions in the executable such that a segmentation fault that would happen, does not (or vice versa).
Depending on the skill level of your team, it can be a good idea to steer them away from risky areas.
Note, throwing an exception in a destructor is undefined behaviour.

When should assertions stay in production code? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
There's a discussion going on over at comp.lang.c++.moderated about whether or not assertions, which in C++ only exist in debug builds by default, should be kept in production code or not.
Obviously, each project is unique, so my question here is not so much whether assertions should be kept, but in which cases this is recommendable/not a good idea.
By assertion, I mean:
A run-time check that tests a condition which, when false, reveals a bug in the software.
A mechanism by which the program is halted (maybe after really minimal clean-up work).
I'm not necessarily talking about C or C++.
My own opinion is that if you're the programmer, but don't own the data (which is the case with most commercial desktop applications), you should keep them on, because a failing asssertion shows a bug, and you should not go on with a bug, with the risk of corrupting the user's data. This forces you to test strongly before you ship, and makes bugs more visible, thus easier to spot and fix.
What's your opinion/experience?
See related question here
Responses and Updates
An assertion is error, pure and simple and therefore should be handled like one.
Since an error should be handled in release mode then you don't really need assertions.
That's why I prefer the word "bug" when talking about assertions. It makes things much clearer. To me, the word "error" is too vague. A missing file is an error, not a bug, and the program should deal with it. Trying to dereference a null pointer is a bug, and the program should acknowledge that something smells like bad cheese.
Hence, you should test the pointer with an assertion, but the presence of the file with normal error-handling code.
Slight off-topic, but an important point in the discussion.
As a heads-up, if your assertions break into the debugger when they fail, why not. But there are plenty of reasons a file could not exist that are completely outside of the control of your code: read/write rights, disk full, USB device unplugged, etc. Since you don't have control over it, I feel assertions are not the right way to deal with that.
Yes, I have Code Complete, and must say I strongly disagree with that particular advice.
Say your custom memory allocator screws up, and zeroes a chunk of memory that is still used by some other object. I happens to zero a pointer that this object dereferences regularly, and one of the invariants is that this pointer is never null, and you have a couple of assertions to make sure it stays that way. What do you do if the pointer suddenly is null. You just if() around it, hoping that it works?
Remember, we're talking about product code here, so there's no breaking into the debugger and inspecting the local state. This is a real bug on the user's machine.
Assertions are comments that do not become outdated. They document which theoretical states are intended, and which states should not occur. If code is changed so states allowed change, the developer is soon informed and needs to update the assertion.
Allow me to quote Steve McConnell's Code Complete. The section on Assertions is 8.2.
Normally, you don't want users to see assertion messages in production code; assertions are primarily for use during development and maintenance. Assertions are normally compiled into the code at development time and compiled out of the code for production.
However, later in the same section, this advice is given:
For highly robust code, assert and then handle the error anyway.
I think that as long as performance is not an issue, leave the assertion in, but rather than display a message, have it write to a log file. I think that advice is also in Code Complete, but I'm not finding it right now.
Leave assertions turned on in production code, unless you have measured that the program runs significantly faster with them turned off.
if it's not worth measuring to prove it's more efficient, then it's not worth sacrificing clarity for a performance gamble." - Steve McConnell 1993
http://c2.com/cgi/wiki?ShipWithAssertionsOn
If you're even thinking of leaving assertions on in production, you're probably thinking about them wrong. The whole point of assertions is that you can turn them off in production, because they are not a part of your solution. They are a development tool, used to verify that your assumptions are correct. But the time you go into production, you should already have confidence in your assumptions.
That said, there is one case where I will turn assertions on in production: If we encounter a reproducible bug in production that we're having a hard time reproducing in a test environment, it may be helpful to reproduce the bug with assertions turned on in production, to see if they provide useful information.
A more interesting question is this: In your testing phase, when do you turn assertions off?
Assertions should never stay in production code. If a particular assertion seems like it might be useful in production code, then it should not be an assertion; it should be a run time error check, i.e. something coded like this: if( condition != expected ) throw exception.
The term 'assertion' has come to mean "a development-time-only check which will not be performed on the field."
If you start thinking that assertions might make it to the field then you will inevitably also start making other dangerous thoughts, like wondering whether any given assertion is really worth making. There is no assertion which is not worth making. You should never be asking yourself "should I assert this or not?" You should only be asking yourself "Is there anything I forgot to assert?"
Unless profiling shows that the assertions are causing performance problems, I say they should stay in the production release as well.
However, I think this also requires that you handle assertion failures somewhat gracefully. For example, they should result in a general type of dialog with the option of (automatically) reporting the issue to the developers, and not just quit or crash the program. Also, you should be careful not to use assertions for conditions that you actually do allow, but possibly don't like or consider unwanted. Those conditions should be handled by other parts of the code.
In my C++ I define REQUIRE(x) which is like assert(x) except that it throws an exception if the assertion fails in a release build.
Since a failed assertion indicates a bug, it should be treated seriously even in a Release build. When my code's performance matters, I will often use REQUIRE() for higher-level code and assert() for lower-level code that must run fast. I also use REQUIRE instead of assert if the failure condition may be caused by data passed in from code written by a third party, or by file corruption (optimally I would design the code specifically to be well behaved in case of file corruption, but we don't always have time to do that.)
They say you shouldn't show those assert messages to end-users because they won't understand them. So? End users may send you an email with a screen shot or some text of the error message, which helps you debug. If the user simply says "it crashed", you have no ability to fix it. It would be better to send the assertion-failure messages to yourself automatically, but that only works if (1) the software runs on a server you control/monitor or (2) the user has internet access and you can get their permission to send a bug report.
If you want to keep them replace them with error handling. Nothing worse than a program just disappearing. I see nothing wrong with treating certain errors as serious bugs, but they should be directed to a section of your program that is equipped to deal with them by collecting data, logging it, and informing the user that your app has had some unwanted condition and is exiting.
Provided they are handled just as any other error, I don't see a problem with it. Do bear in mind though that failed assertions in C, as with other languages, will just exit the program, and this isn't usually sufficient for production systems.
There are some exceptions - PHP, for instance, allows you to create a custom handler for assertion failures so that you can display custom errors, do detailed logging, etc. instead of just exiting.
Our database server software contains both production and debug assertions. Debug assertions are just that -- they are removed in production code. Production assertions only happen if (a) some condition exists that should never exist and (b) it is not possible to reliably recover from this condition. A production assertion indicates that a bug in the software has been encountered or some kind of data corruption has occurred.
Since this is a database system and we are storing potentially enterprise-critical data, we do whatever we can to avoid corrupted data. If a condition exists that may cause us to store incorrect data, we immediately assert, rollback all transactions, and stop the server.
Having said that, we also try to avoid production assertions in performance-critical routines.
Suppose a piece of code is in production, and it hits an assertion that would normally be triggered. The assertion has found a bug! Except it hasn't, because the assertion is turned off.
So what happens now? Either the program will (1) crash in an uninformative way at a point further removed from the source of the problem, or (2) run merrily to completion, likely giving the wrong result.
Neither scenario is inviting. Leave assertions active even in production.
I see asserts as in-line unit tests. Useful for a quick test while developing, but ultimately those assertions should be refactored out to be tested externally in unit tests.
I find it best to handle all errors that are in scope, and use assertions for assumptions that we're asserting ARE true.
i.e., if your program is opening/reading/closing a file, then not being able to open the file is in scope -- it's a real possibility, which would be negligent to ignore, in other words. So, that should have error-checking code associated with it.
However, let's say your fopen() is documented as always returning a valid, open file handle. You open the file, and pass it to your readfile() function.
That readfile function, in this context, and probably according to its design specification, can pretty much assume it's going to get a valid file ptr. So, it would be wasteful to add error-handling code for the negative case, in such a simple program. However, it should at least document the assumption, somehow -- ensure somehow --- that this is actually the case, before continuing its execution. It should not ACTUALLY assume that will always be valid, in case it's called incorrectly, or it's copy/pasted into some other program, for example.
So, readfile() { assert(fptr != NULL); .. } is appropriate in this case, whilst full-blown error handling is not (ignoring the fact that actually reading the file would require some error handling system anyway).
And yes, those assertions should stay in production code, unless its absolutely necessary to disable them. Even then, you should probably disable them only within performance-critical sections.
I rarely use assertions for anything other that compile time type checking. I would use an exception instead of an assertion just because most languages are built to handle them.
I offer an example
file = create-some-file();
_throwExceptionIf( file.exists() == false, "FILE DOES NOT EXIST");
against
file = create-some-file();
ASSERT(file.exists());
How would the application handle the assertion? I prefer the old try catch method of dealing with fatal errors.
Most of the time, when i use assertion in java (the assert keyword) I automatically add some production codes after. According to the case, it can be a logging message, an exception... or nothing.
According to me, all your assertions are critical in dev release, not in production relase. Some of them must be kept, other must be discarded.
ASSERTIONS are not errors and should not be handled as errors. When an assertion is thrown, this means that there is a bug in your code or alternatively in the code calling your code.
There are a few points to avoid enabling assertions in production code:
1. You don't want your end user to see a message like "ASSERTION failed MyPrivateClass.cpp line 147. The end user is NOT you QA engineer.
2. ASSERTION might influence performance
However, there is one strong reason to leave assertions:
ASSERTION might influence performance and timing, and sadly this sometimes matter (especially in embedded systems).
I tend to vote for leaving the assertion on in production code but making sure that these assertions print outs are not exposed to end user.
~Yitzik
An assertion is error, pure and simple and therefore should be handled like one.
Since an error should be handled in release mode then you don't really need assertions.
The main benefit I see for assertions is a conditional break - they are much easier to setup than drilling through VC's windows to setup something that takes 1 line of code.