Assertion vs Exception Handling

D

DT

1. I have a long array and I want to check element of the array fails
my test, for example:

for (int i ...) {
if (a==0) {
cout << "failed " << i << "\n"; break;
}
}

Plus, I only want to compile this error checking code in the debug
mode. If I can use assertion, how to do it? Otherwise, should I use
exception handling and how?

2. If an assertion fails before the cleanup code (i.e. freeing the
pointers), would I experience memory leak? If so, how to avoid such
problems?

Thanks.
 
S

Sprechen sie von C++

you can use #defines to block off debug code that will not be included in
the release.

You could make you code error tolerate with the try/catch approach.
 
V

Vladimir Jovic

DT said:
1. I have a long array and I want to check element of the array fails
my test, for example:

for (int i ...) {
if (a==0) {
cout << "failed " << i << "\n"; break;
}
}

Plus, I only want to compile this error checking code in the debug
mode. If I can use assertion, how to do it? Otherwise, should I use
exception handling and how?

http://www.parashift.com/c++-faq-lite/exceptions.html
http://linux.die.net/man/3/assert


2. If an assertion fails before the cleanup code (i.e. freeing the
pointers), would I experience memory leak? If so, how to avoid such
problems?


If the assertion fails, the OS will clean up.
 
J

John H.

If I can use assertion, how to do it?

There is a standard assert macro provided by #include <cassert>. When
the symbol NDEBUG (think "non-debug") is not defined, assert will
evaluate its argument and if it is false, it will print a brief
diagnostic message and abort the program. When the symbol NDEBUG is
defined, assert does nothing (not even evaluate the argument).
Depending on your development environment, it may offer its own
version of assert, or it may handle asserts differently (for instance,
in a debugger, it might break at the point of a failed assert to give
you a chance to study the situation). You could also create your own
assert mechanism that may have different behavior, as other posters
have discussed.

#include <cassert>
#include <iostream>
void print_name(char const * name)
{
assert(name != NULL);
assert(strlen(name) > 0);
std::cout << name << std::endl;
}

You may find it useful to put some text describing the situation
inside the assert:
assert(name!=NULL && "print_name requires a valid pointer");
This is a trick that relies on the fact that the string literal will
always evaluate to true, so anding it with your test won't change the
logic of your test, but this little description can appear in the
diagnostic message provided when the program aborts.
should I use exception handling and how?

Exceptions can get more complicated. I am not up to a thorough
discussion of them, but I will touch upon them. You can perform
tests, and then throw exceptions, which functions higher up the call
stack may catch and act upon. If no one catches it, the program will
terminate. The above example, with exceptions, might look like:

#include <stdexcept>
#include <iostream>
void print_name(char const * name)
{
if(name == NULL)
throw std::invalid_argument("print_name invalid ptr");
if(strlen(name) < 1)
throw std::length_error("print_name empty name");
std::cout << name << std::endl;
}

A couple things to consider:
- Ease of use:
asserts are simple. You can put in an assert, and it helps you spot
bugs while you run the program. Little development time is spent.
exceptions are more complicated. It's easy to throw an exception, but
that action can cause behavior (via a catch) that might effect the way
the error is seen, and make it harder to track down the origin of the
problem.
This is actually something to think about. Development time is a real
cost in software. Also, if you find one technique a lot of trouble to
use, you may find yourself skipping over programming in such tests
that you will regret later on ("Obviously name isn't going to be
empty, that is just silly, everyone has a name. I am not going to
check for it.").
* Note, the operating system will still clean up some things (like
dynamic memory allocation), but other things that you might want done
(perhaps gracefully closing a network connection) may not happen.

- Flexibility:
asserts offer little flexibility. They are for debug mode only. When
an error is detected, the program is aborted. No destructors are
called, so things might not clean up neatly*.
exceptions offer much flexibility. They will be active in both debug
and release mode. They give a chance for more complicated error
handling. For instance, print_name might throw an exception because
it doesn't have name, but whoever called print_name might be able to
catch it, and add more information to the diagnostic. Destructors are
called so things will clean up more completely.

Another thing you might consider is how serious is the problem. For
instance, say I have an option for the user to get info about the
program, display version number, who it is registered to, etc. If the
code executes, and there is no name, me as a programmer might find it
nice for execution to hault so this unusual state can be brought to my
attention and I can look to see what might be wrong. As an end user,
having a name in an About Box probably isn't a big deal. I certainly
don't want the program to terminate (like an uncaught exception would
do).
In constrast, if I have a function that is about to use a pointer,
dereferencing an invalid pointer could cause the program to crash in
an uncontroled manner, so I probably don't want the user to ever
experience this. In this scenario, an exception might be better.
So here is an example that uses both techniques:
void print_name(char const * name)
{
if(name == NULL)
throw std::invalid_argument("print_name invalid ptr");
assert(strlen(name)>0 && "print_name empty name");
}

Finally, your development environment might also push you one way or
another. Some debuggers will make it more useful to use asserts to
debug, whilst some will make it easier to use exceptions. Play around
and see which one you find more intuitive.
 
J

James Kanze

1. I have a long array and I want to check element of the array fails
my test, for example:
for (int i ...) {
if (a==0) {
cout << "failed " << i << "\n"; break;
}
}


Define what you mean by "fails". Can the case only occur
because of a programming error? Can it occur because of e.g.
resource limitations (insufficient memory, etc.)? Or as a
result of bad user input?
Plus, I only want to compile this error checking code in the
debug mode.

Why? That doesn't normally make sense.
If I can use assertion, how to do it?

Just
assert(a == 0);

But most of the time, assertions will be active in released
code.
Otherwise, should I use exception handling and how?

Whether exception handling or assertions are more appropriate
depends on the type of error and the application domain. And
possibly other considerations as well.
2. If an assertion fails before the cleanup code (i.e. freeing
the pointers), would I experience memory leak? If so, how to
avoid such problems?

An assertion failure terminates your program brutally, with an
abort. The system will clean up most things correctly. And in
cases justifying an assertion failure, you might not want to
clean up others---having the temporary files can help localize
the error.
 
I

Ian Collins

Sigh. What do you mean most of the time? We have been over this before.
By default assert does nothing in release mode which is the way it
should be. Release mode = NDEBUG = "not debugging" = no op assert.

That depends how you define "release mode"

Most of the software I have released was released with assertion on and
most of the code I use (including my preferred C++ compiler) has them
enabled.

I'd rather have a bug report with a core file than one without.
 
M

Michael Doubez

Release mode asserts are desirable only when a higher degree of
defensiveness is required which depends on the application domain in
question.

I would say the definition is the contrary: a program without assert
is possible only when a inconsistent state of the program is
admissible.

I would say it is only possible for programs that don't modify a state
(such as the program ls) and for which you don't care about locating
bug on the user's plateform.
 There is a reason why assert does nothing when NDEBUG is defined.

Because the C standard dictates that when NDEBUG is defined, the
assert macro shall expand to nothing.

NDEBUG has no other effect or meaning whatsoever.

But I find relevant that the assert() are activated by default and it
is a defines that disables them. If assert() was only a debug feature,
I would have expected the reverse: DEBUG enabling asserts.
 
I

Ian Collins

Ian Collins said:
That depends how you define "release mode"

Most of the software I have released was released with assertion on
and most of the code I use (including my preferred C++ compiler) has
them enabled.

I'd rather have a bug report with a core file than one without.
[please don't quote sigs]

Release mode asserts are desirable only when a higher degree of
defensiveness is required which depends on the application domain in
question. There is a reason why assert does nothing when NDEBUG is defined.

Yes there is, you can turn them off. A lot of applications don't. It
may depend on the platform, but most Unix applications I use (and write)
have asserts on; as I said, a bug report with a core file than one
without. If used correctly, asserts trap the unexpected and protect the
integrity of the application's state. I bet whatever C++ compiler you
use has them turned on.

Release mode is a nebulous concept; it means different things to
different people.
 
I

Ian Collins

[please don't quote sigs]
By default VC++ (a *very* popular C++ compiler) defines NDEBUG by
default in release builds.

But I bet asserts are still enabled in the compiler its self.
It doesn't surprise me that unix apps tends to have NDEBUG turned off as
unix traditionally involves writing makefiles by hand so NDEBUG is
something you have to turn on rather than off. I wonder if any popular
unix IDEs turn NDEBUG on by default for release builds.

As I said, release builds means different things to different people.
Unix IDE typically don't do as much hand holding as the likes of VC++.
I've never released anything with assertion off, even on small embedded
platforms.
 
I

Ian Collins

From Microsoft documentation:

The assert macro is typically used to identify logic errors during
program development by implementing the expression argument to evaluate
to false only when the program is operating incorrectly. After debugging
is complete, assertion checking can be turned off without modifying the
source file by defining the identifier NDEBUG. NDEBUG can be defined
with a /D command-line option or with a #define directive. If NDEBUG is
defined with #define, the directive must appear before ASSERT.H is
included.

Yes, we all know what NDEBUG does, that's not the contentions issue.
Notice the use of the word "typically". My point is that *typically*
assert is a debugging tool used during the development phase and only
rarely enabled for released product where a higher degree of
defensiveness is appropriate. Yes I admit I am a Microsoft fanboy. You
are a unix fanboy.

That's where I beg to differ, if you were to conduct a survey, you'd
probably be surprised how many application do ship with asserts on.
Games are probably an exception, but any application that manipulates
user data will want to verify the sanity of its internal state.

I don't develop for windows, but isn't it asserts that pop up that
dialogue box asking if you want to debug or abort (if you have VC++
installed) an application when it goes wrong?
 
I

Ian Collins

NDEBUG is defined by default for release builds when creating a new
project with VC++. assert is a no-op when NDEBUG is defined. I have no
idea what you mean by "asserts are still enabled in the compiler its
self". assert(foo) does nothing when NDEBUG is defined in VC++ which is
as it should be.

When they build the compiler, they don't define NDEBUG. I'm sure I've
seen report of compiler assertions form VC++. I've certainly hit a few
in g++ and Sun CC.
 
I

Ian Collins

I have no idea what you are talking about. Who cares how the compiler
was built? It is irrelevant to building software with the compiler.

It is completely relevant to the discussion as a counter example to your
point: "that *typically* assert is a debugging tool used during the
development phase and only rarely enabled for released product"

If something unexpected happens and the compiler's internal state
becomes corrupt, do you want it to generate bad code, fall in a heap or
bail with an assertion failure? As both a user and a developer, I know
which one I'd prefer.
 
I

Ian Collins

That is what will happen if NDEBUG was not defined when the asserting
statement was compiled and the assert evaluates to false.

I thought so.

So asserts are enabled in the likes of Word and Excel as well (I've seen
this dialogue from both). Which to my mind is a jolly good thing.
 
I

Ian Collins

I misunderstood. Yes I agree, I already said there are exceptions where
a higher degree of defensiveness may be required and a compiler might be
such an exception as it can be used to compile software which might
itself require a higher degree of defensiveness. This doesn't change the
fact that assert is primarily a debugging aid.
Ah, good we are on the same wavelength at last.

I still disagree with assert being primarily a debugging aid. Unit
tests should be the debugging tool, asserts are the safety net for those
unexpected events that can't be handled by the application's logic.

I may be biased coming from an embedded background, but one of the first
lessons an embedded developer learns is to expect the unexpected and
defend against it. A typical real example was a driver I wrote for a
serial device; according the data sheet, it was impossible for the data
read interrupt to fire with an empty input buffer. So I added an
assertion in the interrupt handler. Sure enough, in a customer site,
the product rebooted. The log showed that assert had triggered.
 
J

James Kanze

news:3494792b-bcd9-4426-a762-3701ff3673ae@y17g2000yqd.googlegroups.com...
1. I have a long array and I want to check element of the array fails
my test, for example:
Just
assert(a == 0);
But most of the time, assertions will be active in released
code.

Sigh. What do you mean most of the time?

I mean most of the time in programs written by professional
programmers, using well established techniques for project
management.

Obvious, hobby programmers have their own rules, with which I'm
not familiar.
We have been over this before.

Yes. The issue is pretty well established, and well documented
in the appropriate literature.
By default assert does nothing in release mode which is the
way it should be.

There is no real default, or at least not one applicable to any
real applications. Every application will decide what to do
with regards to all of the compiler options. Of course, the
very fact that one speaks of a "release mode" suggests
unprofessionalism. If at all possible, you "release" the code
you've tested, and there aren't different modes. (And when not
possible, there may be more than just two modes.)
 
J

James Kanze

On 03/12/10 11:36 PM, Leigh Johnston wrote:

That depends how you define "release mode"
Most of the software I have released was released with
assertion on and most of the code I use (including my
preferred C++ compiler) has them enabled.
I'd rather have a bug report with a core file than one without.

And I'd rather release the executables that I've tested, rather
than something else. (One recent but I had to track down was
due to the fact that VC++ doesn't always call destructors when
optimization is turned on---in the Visual IDE's "release mode".
And that in the code in question, smart pointers were an
appropriate solution, and were being used.)
 
R

Robert Fendt

There is no real default, or at least not one applicable to any
real applications. Every application will decide what to do
with regards to all of the compiler options. Of course, the
very fact that one speaks of a "release mode" suggests
unprofessionalism. If at all possible, you "release" the code
you've tested, and there aren't different modes. (And when not
possible, there may be more than just two modes.)

Well, you do live in a very interestingly limited world it
seems. And labeling more or less everyone who does not agree
with you as unprofessional is quite an interesting statement as
well.

At my company, we _do_ have two different builds, one for
debugging and one for release. The application is very
performance-sensitive. In the debugging version, all sorts of
sanity checks and asserts are active, which slow the code down
by an additional factor of 5-10 (apart from the lack of
optimisation), but which help to make sure that the geometry
core is in fact doing something mathematically sane.

Apart from that, asserts do not always make sense in non-debug
code anyway. For example, I currently also develop a graphics
transformation library. If I build it with fully optimisation,
it becomes faster by a factor of 10-20 (among other things due
to massive inlining). However, it is more or less _impossible_
to debug when built fully optimised, so active asserts would not
do much good anyway.

By the way, the standard 'assert' macro defined in the standard
IIRC is explicitely disabled if 'NDEBUG' is defined, and setting
this preprocessor symbol also disables all sorts of range checks
etc. in STL containers at least in VC++, if I am not mistaken.
So in my opinion it could in fact be quite common that asserts
are inactive in production code, at least if it is
performance-critical code built with full optimisation.

Regards,
Robert
 
J

James Kanze

Release mode asserts are desirable only when a higher degree
of defensiveness is required which depends on the
application domain in question. There is a reason why assert
does nothing when NDEBUG is defined.
[/QUOTE]
Yes there is, you can turn them off. A lot of applications
don't. It may depend on the platform, but most Unix
applications I use (and write) have asserts on; as I said, a
bug report with a core file than one without. If used
correctly, asserts trap the unexpected and protect the
integrity of the application's state. I bet whatever C++
compiler you use has them turned on.

The standard requires assertions to be active unless they are
explicitly disabled (by defining NDEBUG). The standard also
very explicitly allows including <assert.h> multiple times,
changing whether NDEBUG is defined between the inclusions. The
intent is clearly to allow turning off assertions in a very
controled manner, since you can include <assert.h> multiple
times, and the definition of assert will change each time.

All of the compilers and IDE's that I know (Sun CC, g++, Visual
Studios) have "defaults" set for just playing around. They're
fine if you just want to quickly try something out, but you
wouldn't use them in production code. This is doubtlessly
because there is no one set of defaults that would be
appropriate for all types of production code, so anyone
developing code professionally will read the compiler
documentation, and decide what options are appropriate for his
application.
Release mode is a nebulous concept; it means different things
to different people.

Release mode means whatever set of options are used in the code
you release. If at all possible, that will be the same set as
you used to develop the code---I don't like the idea of
releasing code compiled with different options than those I've
tested. There are, however, valid reasons for differences: you
might not what the debugging symbol tables in the released code,
for example. There are even specific cases where you might want
to turn off assertions, at least in critical sections of your
code, and under Windows, it's usually appropriate to catch
SIGABRT, and to intercept structured exceptions, in order to
prevent the silly pop-up window you'll get otherwise.
 
J

James Kanze

[...]
From Microsoft documentation:

Just a note, but Microsoft documentation (like the documentation
of all other compilers) describes the possibilities of the
compiler; it does not define "best practices", nor does it
pretend to.
The assert macro is typically used to identify logic errors
during program development by implementing the expression
argument to evaluate to false only when the program is
operating incorrectly. After debugging is complete, assertion
checking can be turned off without modifying the source file
by defining the identifier NDEBUG. NDEBUG can be defined with
a /D command-line option or with a #define directive. If
NDEBUG is defined with #define, the directive must appear
before ASSERT.H is included.
Notice the use of the word "typically". My point is that
*typically* assert is a debugging tool used during the
development phase and only rarely enabled for released product
where a higher degree of defensiveness is appropriate.

But there's certainly nothing in what you quoted that would
support that point of view.
Yes I admit I am a Microsoft fanboy. You are a unix fanboy.
Fanboys should probably be mostly ignored - but I don't give
a ****. :)

Well, I'm not a fanboy. For various reasons, most of my
experience has been on Sun platforms, but I'm currently working
in a mainly Windows environment, and while there are some
definite diffences, basic issues of the development process
are the same.
 
J

James Kanze

[...]
I don't develop for windows, but isn't it asserts that pop up
that dialogue box asking if you want to debug or abort (if you
have VC++ installed) an application when it goes wrong?

That depends on the compiler options: you can chose between that
and a structured exception. If neither is appropriate (usually
the case when developing libraries, since you want to test that
your assertions trigger correctly), then you need to specify no
structured exceptions, explicitly catch SIGABRT, and also tell
the system that you don't want the popup otherwise, by calling
SetErrorMode.

This information is apparently well known in the Microsoft
community, because I hardly had to mention the issue in a
Microsoft forum to get a complete explination. I think you'll
find that a lot of Microsoft programmers are very professional
as well, and are capable of specifying what is appropriate for
their application as well.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,058
Latest member
QQXCharlot

Latest Threads

Top