Place Assert in Exception

I

Immortal Nephi

You can write your own assert macro. I have seen that assert macro
always use either abort() or terminate(). abort() causes serious
problems if it does not call class’ destructor to deallocate memory.
Memory leak is getting worse and the performance is dropped from the
operating system while you call abort() many times.
Exception handler is the best option over abort(). You can write
your own message box in either windows or console.
I write Error_Report class. Error_Report class is different from
exception class because it does not require inheritance. All the data
members and member functions of Error_Report have static storage.
Static storage is required. If you do not declare static, then after
throw is invoked, throw calls Error_Report’s constructor and
destructor before both data members pop out of stack and going to the
catch block.
You can add error messages to the enum block. You use assert macro
to select error message.
I have seen many arguments against placing exception in assert.
My code looks very clear. You can always customize message box, but
assert macro is not changed.


#include <iostream>
#include <string>
#include <sstream>

class Error_Report {
public:
enum Code {
OUT_OF_RANGE,
POINTER_NULL,
NORMAL
};

enum Behavior {
e_ABORT,
e_RETRY,
e_IGNORE,
};

Error_Report( Code _code ) {
code = _code;
}

~Error_Report() {
}

static char* What() {
return Error_Report::message[ code ];
}

static Behavior Assert(
Code _code,
const char* File,
const int LineNumber,
const char* Function ) {

std::eek:stringstream text;

text << "Debug Assertion Failed!\n\nFile: " << File <<
"\nLine: " << LineNumber << "\nFunction: " << Function <<
"\n\nExpression: " << message[ _code ] <<
"\n\nFor information on how your program can cause a report\n" <<
"failure, see the Visual C++ documentation on asserts.\n\n";

std::string prompt;
bool condition = true;

std::cerr << text.str(); // you can use MessageBox instead

while( condition ) {
std::cerr << "(Press 'A' key to abort or press 'I' to ignore)\n" <<
"(Press 'R' key to debug the application)\n"
"Prompt: ";

std::ws( std::cin );
std::getline( std::cin, prompt );

if( prompt == "A" || prompt == "a" )
// abort();
throw Error_Report( _code );

else if( prompt == "R" || prompt == "r" )
return e_RETRY;

else if( prompt == "I" || prompt == "i" )
return e_IGNORE;

std::cerr << "\n\nInvalid input. Try again.\n";
}

return e_IGNORE; // not used here
}

private:
static Code code;
static char* message[ 3 ];
};

Error_Report::Code Error_Report::code = Error_Report::NORMAL;
char* Error_Report::message[ 3 ] = {
"Out of range",
"pointer null",
"Normal"
};

#define ASSERT( Expression, Message ) \
if( !( Expression ) ) { \
if( Error_Report::e_RETRY == Error_Report::Assert( \
Message, \
__FILE__, \
__LINE__, \
__FUNCTION__ ) ) \
__debugbreak(); \
}


int main() {
try {
int x = 5;

ASSERT( x < 4, Error_Report::OUT_OF_RANGE );
}
catch ( Error_Report &e ) {
std::cerr << "Error_Report: " << e.What() << endl;
}

return 0;
}
 
I

Ian Collins

You can write your own assert macro. I have seen that assert macro
always use either abort() or terminate(). abort() causes serious
problems if it does not call class’ destructor to deallocate memory.
Memory leak is getting worse and the performance is dropped from the
operating system while you call abort() many times.

It won't if the OS is doing its job.
Exception handler is the best option over abort(). You can write
your own message box in either windows or console.

Assuming you have either.
I write Error_Report class. Error_Report class is different from
exception class because it does not require inheritance. All the data
members and member functions of Error_Report have static storage.

Exceptions don't require inheritance, what's your point?
Static storage is required. If you do not declare static, then after
throw is invoked, throw calls Error_Report’s constructor and
destructor before both data members pop out of stack and going to the
catch block.
You can add error messages to the enum block. You use assert macro
to select error message.
I have seen many arguments against placing exception in assert.
My code looks very clear. You can always customize message box, but
assert macro is not changed.

But what it is built on a fallacy, namely "abort() causes serious problems".
#include<iostream>
#include<string>
#include<sstream>

class Error_Report {
public:
enum Code {
OUT_OF_RANGE,
POINTER_NULL,
NORMAL
};

enum Behavior {
e_ABORT,
e_RETRY,
e_IGNORE,
};

Error_Report( Code _code ) {
code = _code;
}

~Error_Report() {
}

static char* What() {
return Error_Report::message[ code ];
}

static Behavior Assert(
Code _code,
const char* File,
const int LineNumber,
const char* Function ) {

std::eek:stringstream text;

text<< "Debug Assertion Failed!\n\nFile: "<< File<<
"\nLine: "<< LineNumber<< "\nFunction: "<< Function<<
"\n\nExpression: "<< message[ _code ]<<
"\n\nFor information on how your program can cause a report\n"<<
"failure, see the Visual C++ documentation on asserts.\n\n";

Why would I want to "see the Visual C++ documentation on asserts"?
 
I

Immortal Nephi

It won't if the OS is doing its job.


Assuming you have either.


Exceptions don't require inheritance, what's your point?

No, it is not correct. Exception class has inheritance. Look at
stdexcept header. Several classes are derived from exception class.
For example, you call out_of_range() before the constructor in turn
calls exception constructor. exception class has virtual functions.
   Static storage is required.  If you do not declare static, then after
throw is invoked, throw calls Error_Report’s constructor and
destructor before both data members pop out of stack and going to the
catch block.
   You can add error messages to the enum block.  You use assert macro
to select error message.
   I have seen many arguments against placing exception in assert.
   My code looks very clear.  You can always customize message box, but
assert macro is not changed.

But what it is built on a fallacy, namely "abort() causes serious problems".
class Error_Report {
public:
   enum Code {
           OUT_OF_RANGE,
           POINTER_NULL,
           NORMAL
   };
   enum Behavior {
           e_ABORT,
           e_RETRY,
           e_IGNORE,
   };
   Error_Report( Code _code ) {
           code = _code;
   }
   ~Error_Report() {
   }
   static char* What() {
           return Error_Report::message[ code ];
   }
   static Behavior Assert(
           Code _code,
           const char* File,
           const int LineNumber,
           const char* Function ) {
           std::eek:stringstream text;
           text<<  "Debug Assertion Failed!\n\nFile: "<<  File<<
                   "\nLine: "<<  LineNumber<<  "\nFunction: "<<  Function<<
                   "\n\nExpression: "<<  message[ _code ]<<
                   "\n\nFor information on how your program can cause a report\n"<<
                   "failure, see the Visual C++ documentation on asserts.\n\n";

Why would I want to "see the Visual C++ documentation on asserts"?

Like I said before. You can customize Assert function of
Error_Report class. You add platform specification macros. It can go
to Windows, Linux, Mac OSX, or other operating system. Also, you can
tell which C++ Compiler is Microsoft or GCC or Intel.
You do customize text message. Abort, Retry, Ignore option is not
changed.
Please tell me what you think Error_Report class? Is throw better
than abort()?
 
I

Ian Collins

Please note this.
No, it is not correct. Exception class has inheritance. Look at
stdexcept header. Several classes are derived from exception class.
For example, you call out_of_range() before the constructor in turn
calls exception constructor. exception class has virtual functions.

It is correct, not all exception classes have to derive from
std::exception. Anyway, what is wrong with an exception class tree?

You didn't address this key point.
Like I said before. You can customize Assert function of
Error_Report class. You add platform specification macros. It can go
to Windows, Linux, Mac OSX, or other operating system. Also, you can
tell which C++ Compiler is Microsoft or GCC or Intel.
You do customize text message. Abort, Retry, Ignore option is not
changed.

I don't think your class adds any value, exceptions and asserts are
different beasts.
Please tell me what you think Error_Report class? Is throw better
than abort()?

That is a silly question. Whether throw is better than abort depends
entirely on context.
 
J

James Kanze

Ian Collins ha scritto:
Not to mention that in C++ you may throw everything if you
really wish so, even primitives.

Quite. I very often throw int's.

The real issue with regards to the original posting is whether
to use assert or throw an exception. And the only answer is: it
depends. It depends on the type of error, and on the context
the program is running. There is no absolute rule. But you
certainly don't want to replace all asserts with something that
throws an exception, That's a sure fire solution for creating
problems.
 
J

James Kanze

If you are writing a library that others will be using, then
it is not up to you to decide to summarily abort their app.

Yes and no. If they violate the contract of your library,
summarily terminating their application is probably the best
solution (in most applications).
Note that assert is never used by the standard library;

Really? It is in the implementations I'm familiar with.
Anytime the library detects you've done something that the
standard specifies is undefined behavior.
 
Ö

Öö Tiib

Again, I don't see where that is up to you since you are not the
application writer and you don't know if the particular application that
your library is being used in qualifies under the phrase "most
applications" or if this particular situation is a special case.

When designing library, then it is best to write as forgiving contract
for input as possible and give as strict output as possible. One can
not write endlessly forgiving software however. Then they write into
contract that such input they assert and on violation they abort. Also
they have unit test about it. Library users have to be software
developers too and if they do not want aborts then they should not
call for these.
Asserts may very well be used in particular implementations of the
standard library, where the standard doesn't specify the result of an
operation, but the standard itself never specifies that doing X will
cause an assert to fire, but it does make such specifications about
exceptions.

Current standard uses too lot of that "undefined behavior" at places
where library can easily assert. Most good compilers have asserts at
such places under certain compiler options in standard library. As
real library designer you want to have as few of such undefined
behaviors as possible. Otherwise you will get numerous issue reports
how your library crashes and what not. Standard is therefore bad
guiding light here.

On the other hand there are plenty of places specified by standard
where your own code may not throw when interacting with standard
library without causing undefined behavior. You still may be unable to
proceed in sane manner within such a code. Assert is one reasonable
option at such places.
 
Ö

Öö Tiib

Again, I don't see where that is up to you since you are not the
application writer and you don't know if the particular application that
your library is being used in qualifies under the phrase "most
applications" or if this particular situation is a special case.

When designing library, then it is best to write as forgiving contract
for input as possible and give as strict output as possible. One can
not write endlessly forgiving software however. Then they write into
contract that such input they assert and on violation they abort. Also
they have unit test about it. Library users have to be software
developers too and if they do not want aborts then they should not
call for these.
Asserts may very well be used in particular implementations of the
standard library, where the standard doesn't specify the result of an
operation, but the standard itself never specifies that doing X will
cause an assert to fire, but it does make such specifications about
exceptions.

Current standard uses too lot of that "undefined behavior" at places
where library can easily assert. Most good compilers have asserts at
such places under certain compiler options in standard library. As
real library designer you want to have as few of such undefined
behaviors as possible. Otherwise you will get numerous issue reports
how your library crashes and what not. Standard is therefore bad
guiding light here.

On the other hand there are plenty of places specified by standard
where your own code may not throw when interacting with standard
library without causing undefined behavior. You still may be unable to
proceed in sane manner within such a code. Assert is one reasonable
option at such places.
 
I

Immortal Nephi

Again, I don't see where that is up to you since you are not the
application writer and you don't know if the particular application that
your library is being used in qualifies under the phrase "most
applications" or if this particular situation is a special case.



Asserts may very well be used in particular implementations of the
standard library, where the standard doesn't specify the result of an
operation, but the standard itself never specifies that doing X will
cause an assert to fire, but it does make such specifications about
exceptions.

Now, can you please answer my question? Why doesn’t abort() call all
class’ destructors to deallocate memory before the application is
terminated?
 
Ö

Öö Tiib

        Now, can you please answer my question?  Why doesn’t abort() call all
class’ destructors to deallocate memory before the application is
terminated?

You about Windows? Because then DrWatson can store the situation for
sending to developers for further examination. If there are no such
DrWatsons present then Windows will release everything anyway so why
to bother?
 
I

Ian Collins

Now, can you please answer my question? Why doesn’t abort() call all
class’ destructors to deallocate memory before the application is
terminated?

Because the application may not be in a fit state to call anything. If
an assert is triggered by heap corruption, what do you think will happen
if the application attempts to deallocate memory?

What use would a core file be if it didn't reflect the exact state of
the application when the assert fired?

You still appear to be labouring under the mistaken belief that
terminating an application without freeing memory causes a memory leak.
 
J

James Kanze

Again, I don't see where that is up to you since you are not
the application writer and you don't know if the particular
application that your library is being used in qualifies under
the phrase "most applications" or if this particular situation
is a special case.

Yes. The ideal case is to use a callback, which defaults to
aborting. But few libraries, starting with the standard
library, do. The usual convention is to say that contract
violations are undefined behavior---the the client code simply
doesn't have the right to violate the contract, and if he does,
he gets whatever you decide to give him.

Note that in the same way, as a library writer, you don't know
that the application is prepared to handle such exceptions, so
by the same argument that you use against aborting, you can't
throw an exception either.
Asserts may very well be used in particular implementations of
the standard library, where the standard doesn't specify the
result of an operation, but the standard itself never
specifies that doing X will cause an assert to fire, but it
does make such specifications about exceptions.

Yes. Exceptions are part of the contract. You can count on
them. Undefined behavior is not part of the contract, and the
standard doesn't want to impose on an implementation the cost of
verifying it. In practice, all implementations which do verify
it trigger an assertion failure. (Of course, under Windows, you
can configure things so that an assertion failure results in an
exception. If yours is one of the rare applications where that
is more appropriate.)
 
J

James Kanze

On Oct 10, 1:14 pm, "Daniel T." <[email protected]> wrote:

[...]
Now, can you please answer my question? Why doesn’t abort()
call all class’ destructors to deallocate memory before the
application is terminated?

Because it's not supposed to. It does deallocate all resources
belonging to the process. I don't know where you get the idea
that an assert will leak. But if the internal state of the
program is inconsistent, and can't be trusted, you want to
execute as little code as possible before getting out of there.
Any code you execute may make things worse.
 
J

Joshua Maurice

If you are writing a library that others will be using, then it is not
up to you to decide to summarily abort their app.

I politely disagree.
Note that assert is
never used by the standard library; it only throws.

Really? I'm pretty sure I could get all commercial C++ standard
library implementations to abort (or equivalent death) through
improper usage.
However, most code
is not library code.

Now this seems really dubious. I suppose it depends on your definition
of library. If a library is only a piece of code which is written by
one company and another company writes code against it, then maybe.
However, internal to those organizations are smaller organizations,
teams if you will, which produce libraries for other teams. Moreover,
any sane coding style includes decoupling, and these decoupled
components are usually properly called libraries, so even a single
team often has most of their code in libraries.

However, to address your central point: We've had this discussion
before, and I'm sure we'll have it again. Some people (including a
large portion of the C++ professionals) think that abort and killing
the process is a fine way to handle some kinds of "errors" and
sometimes throwing an exception is a fine way of handling other kinds
of "errors". Others insist that killing the process is never
acceptable. I believe that these people are wrong.

It's all about robustness and correctness in the face of errors, user
errors, programmer errors, network errors, and so on. It is my belief
based on evidence that robustness and correctness is best served by
judicious use of abort, and that one should generally not throw an
exception in C++ code when encountering an unexpected error, aka a
failed "sanity check", aka the traditional use of asserts.

Please see google for the voluminous amount of debate on this topic,
including many in these newsgroups.
 
J

Joshua Maurice

        Now, can you please answer my question?  Why doesn’t abort() call all
class’ destructors to deallocate memory before the application is
terminated?

Because that's not abort. That's exit. Different functions for a
reason.

If you're intending to ask why doesn't assert call exit instead of
abort, see the other replies else-thread discussing when it's ok to
bring down the process when encountering some kinds of errors. In
short, the professional C++ thinking is that the traditional and
intended use of assert is to do "sanity checks", and if a sanity check
fails, then the process should be immediately brought down before it
can do any more harm, preferably in a debuggable state.
 
G

Gennaro Prota

Yes. The ideal case is to use a callback, which defaults to
aborting. But few libraries, starting with the standard
library, do.

In that regard, the only solution I've seen in actual usage is
link-time customization, where the user links his own
assertion_fired() function. That's not the usual way to "pass" a
callback but, in the essence, it's just that.
The usual convention is to say that contract
violations are undefined behavior---the the client code simply
doesn't have the right to violate the contract, and if he does,
he gets whatever you decide to give him.

Note that in the same way, as a library writer, you don't know
that the application is prepared to handle such exceptions, so
by the same argument that you use against aborting, you can't
throw an exception either.

Yes. And trying to cope with such "unknowns" is very often a
path to premature generalization. In practice your library
offers a contract; applications for which that contract does not
fit will have to simply discard the library. You may decide to
offer a "richer" contract (with callbacks, etc.). Or not. But,
as always, there's no one size fits all, despite the several
libraries around which promise otherwise.
 
J

Jorgen Grahn

On Oct 10, 12:04 pm, Immortal Nephi <[email protected]>
wrote: ....

Because that's not abort. That's exit. Different functions for a
reason.

But exit() doesn't call any destructors either! What you want to do
at normal termination is to return from main().

/Jorgen
 
J

James Kanze

But exit() doesn't call any destructors either! What you want to do
at normal termination is to return from main().

It calls the destructors for most static objects. And it
flushes the streams.

Still, it doesn't do as much as we'd like. If that's a problem,
try wrapping all of the code in main in a try {...} catch (int
returnCode ) { return returnCode; }, and throwing an int.
 
I

Ian Collins

It calls the destructors for most static objects. And it
flushes the streams.

Still, it doesn't do as much as we'd like. If that's a problem,
try wrapping all of the code in main in a try {...} catch (int
returnCode ) { return returnCode; }, and throwing an int.

Or if you really want to clean something up, use atexit().
 
J

Jorgen Grahn

I politely disagree.

Yes. If the caller breaks the preconditions, I have the right to do
what I want. Asserting is one of the more polite things you can do
here.
Really? I'm pretty sure I could get all commercial C++ standard
library implementations to abort (or equivalent death) through
improper usage.


Now this seems really dubious. I suppose it depends on your definition
of library. If a library is only a piece of code which is written by
one company and another company writes code against it, then maybe.

More than "maybe" -- such code is obviously a small part of all C++ code!
However, internal to those organizations are smaller organizations,
teams if you will, which produce libraries for other teams. Moreover,
any sane coding style includes decoupling, and these decoupled
components are usually properly called libraries, so even a single
team often has most of their code in libraries.

I disagree here, at least partly. Sure, in a large organization
you have components, and there are big groups of people who really
only want to deal with the interfaces of most components. But it
doesn't follow that the rules need to be the same as for a proprietary
3rd party library:

- you only have one set of users, and you work towards the
same deadlines
- you only have one purpose
- you have no secrets to each other; no money[1] and no contracts

I'm saying this because I believe it's harmful to try to emulate "true"
3rd party libraries within an organization -- isolating the library
writers from the library users, hiding away the source code, and so on.

/Jorgen
 

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,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top