Click to See Complete Forum and Search --> : Can C++ programs use C libraries?


scorpicorn
January 24th, 2003, 07:56 AM
I have a C program which is required to call functions in a C library which I do not have the source codes. However, the library crashes my program due to some unknown exceptions, probably due to pointers errors, but they occur very rarely.

I was thinking of converting my C program to C++. This way, it will be possible to make use of the exception handling mechanisms of C++, such that my program will not crash when errors occur in the library again.

Can C++ programs use C libraries in the first place? How else can I prevent errors in the library from crashing my program???

PaulWendt
January 24th, 2003, 08:46 AM
Yes, C++ programs can use C libraries. You just have to use
extern "C" so that name mangling will be suppressed. Since you
are getting a crash, you're obviously linking so you know this.

One possible source of errors is that some C function is creating
memory with malloc() and you're getting rid of that memory with
delete. Mixing malloc() and free() with new and delete is a fairly
common source of errors when mixing C and C++.

--Paul

stober
January 24th, 2003, 08:53 AM
I never had a problem with using malloc(), free(), new and delete all in the same program. Just have to remember that when you call malloc() you must use free(), and when you use new you must use delete. So, your C++ code must use free() to release any memory allocated in the C library (unless it was allocated by some other unusual way such as LocalAlloc(). Most 3d party libraries I've seen have that well documented.

RNEELY
January 24th, 2003, 09:11 AM
scorpion,

can you be more specific?
what compiler, OS, library?
what are the symptoms of the crash?

regards,
-ron

AnthonyMai
January 24th, 2003, 10:19 AM
I have a C program which is required to call functions in a C library which I do not have the source codes. However, the library crashes my program due to some unknown exceptions, probably due to pointers errors, but they occur very rarely.

I was thinking of converting my C program to C++. This way, it will be possible to make use of the exception handling mechanisms of C++, such that my program will not crash when errors occur in the library again.

Can C++ programs use C libraries in the first place? How else can I prevent errors in the library from crashing my program???


It is NOT necessary to use C++ exception mechanism to catch an exception thrown from some C library. Because there is no way a C library can throw a C++ exception. Even if it wants, it hasn't learned how to throw C++ exception yet!!! The exception is either triggered by some C code, and there is C ways to handle it. The exception may be trigered by the OS, and then there is OS ways to handle it. The C code could even be triggered by the CPU hardware, and there is CPU hardware way of handling them.

For topics of how C code can trigger and catch exceptions, search for stuff like "longjmp", "setjmp". Actually all C++ exception stuff boils down to the C long jump etc underneath.

C++ exceptions are fundamentally BAD thing in programming. Avoid using them at all cost. Prior to C++, in the long history of C programming, people rarely used longjmp(), setjmp etc.. even though it is defined. There are good reasons to it. Once C++ exception is invented, people begin to abuse C++ exceptions, which boils down to use the setjmp and longjmp that historically never been used. That is BAD.

In the OP's specific problem. What you need to do is not trying to catch the crash in the C library. If it is the fault of you pass the wrong parameters, then correct your own code. If it is the fault of the library itself doing something wrong, then debug the library. If it is a third party library that happen to be crappy. Then there is nothing you can do other than telling them that and turn around and by another product from a fourth party vendor.

KevinHall
January 24th, 2003, 10:45 AM
I think Anthony may be correct about C not being able to create exceptions and about how you should research your problem.

If it is a problem with the third party library, then you should check with the people who made the library. They may have a newer version that fixes the bug you are seeing or if they have never seen the bug, they may work with you to solve the problem and then provide you a fixed library. If this doesn't work out, then you may want to investigate other libraries or (gulp...) some workaround of your own if you *must* use their library.

- Kevin

Sef
January 24th, 2003, 11:07 AM
> C++ exceptions are fundamentally BAD thing in
> programming. Avoid using them at all cost.

You're free to hold whatever views you want as usual but others should take note. Nothing is perfect and exceptions are no exception (bad pun not intended). Anthony's views are nevertheless considered extreme by most developers. To simply call them BAD and advocate against their use "at all costs" flies in the face of what most would consider balanced judgment. And as I recall from one long discussion on the matter a year or two ago, you didn't seem to be aware of exception specifications so the point you were arguing was ill-formed (and wrong). I don't say this to start a fight on the subject (I won't respond) but all newcomers should do their own research first (and consider why exceptions - a feature that has solid advantages over return codes and which most developers appreciate - made it to standard in the first place).

KevinHall
January 24th, 2003, 11:45 AM
I also have to agree with Sef here (and I'm not looking to participate in a fight either).

stober
January 24th, 2003, 11:58 AM
I used to think SetJmp() and LongJmp() were soooo cool when I was writing C code that I used it quite often to return from very deeply nested function calls. Relieved me from writing a lot of complex function return code checks. I missed it alot when I started writing C++ code but eventually found better ways of doing that. Now, I don't write C code anymore, but rarely use exceptions (try/catch blocks) unless I KNOW that some 3d party or M$ Win32 API function could cause one.

Anthony is correct though -- they should never be used to cover-up a program bug.

galathaea
January 25th, 2003, 12:20 AM
Originally posted by scorpicorn
I have a C program which is required to call functions in a C library which I do not have the source codes. However, the library crashes my program due to some unknown exceptions, probably due to pointers errors, but they occur very rarely.

I was thinking of converting my C program to C++. This way, it will be possible to make use of the exception handling mechanisms of C++, such that my program will not crash when errors occur in the library again.

When this occurs, it is often time to move away from a legacy library and look for alternative acquisitions. But I understand that it is often not possible to do this immediately, because companies (particularly small ones) have to count their costs. So you may need to patch it up for meantime...

Unfortunately, the best solution will have an OS dependency. You have to rely on any OS method of failure notification available (signals, interrupts, exceptions (like Windows, not c++), etc.), and program their proper operation through the OS API. You could even throw on a hierarchy abstraction manager (like an Abstract Factory) if you needed to still work in different OSes, to make it easier and quicker to compile updates. This probably wouldn't require you going out of c if there were no other reasons for you to switch to c++.

Originally posted by AnthonyMai
C++ exceptions are fundamentally BAD thing in programming. Avoid using them at all cost. Prior to C++, in the long history of C programming, people rarely used longjmp(), setjmp etc.. even though it is defined. There are good reasons to it. Once C++ exception is invented, people begin to abuse C++ exceptions, which boils down to use the setjmp and longjmp that historically never been used. That is BAD.

I agree that exceptions are often badly used, particularly smaller projects where the reasons for using them are often unclear. However, exceptions are in the c++ language for some very good reasons. There are certain very particular types of problems which require either exception handling or catastrophic program failure, namely: memory allocation failures (catch those news) and other failures that compromise the integrity of the environment.

In large applications (such as terabyte databases, cinematic 3d (modeling, special effects, and animation), modern computer games...) that may have very valuable information on them, you do not want catastrophic program failure. But, the problem is that you often cannot return an error code because the particular mechanism of returning may not function. For example, if a memory allocation failure occurs, it is likely a copy ctor call will fail as well. Exceptions let us to reverse down the call stack, allowing resource objects to free themselves as they distruct, in effect rolling back in a controlled manner the environment. This is much safer (particular if we give our destructors the strong guarantee), as it is mainly executions and resource deallocation. With exceptions, catastrophic program failures are mainly left to programming error, OS failure, or hardware failure (and many of these can be cleaned up with proper error checking programming practices and interfacing with the OS API).

Sef
January 25th, 2003, 10:21 AM
Originally posted by galathaea

There are certain very particular types of problems which require either exception handling or catastrophic program failure, namely: memory allocation failures (catch those news) and other failures that compromise the integrity of the environment.

There's a "nothrow" version of new that returns a NULL pointer if you want but his point is that you should never throw yourself. He believes you're only required to work with exceptions when you *have* to (e.g., you're catching a 3rd-party exception for instance). I don't know how he expects operator overloading (and chaining) to report an error but that's just one issue. In any case, this was debated in the past so you can read his record on the subject but he's completely misguided IMO. I don't believe he's fully considered the issues and that's meant without insult. As I recall for instance, he once claimed that functions don't know who's actually responsible for catching an exception which is clearly false - the exception specification tells you that a function may throw and you can catch it if you want or let it propagate up the call stack - fundamentally that's no different than manually propagating a return code, a concept he clearly advocates. Here's just one lengthy thread but I believe there are others:

http://www.codeguru.com/forum/showthread.php?s=&threadid=132249&highlight=exceptions

AnthonyMai
January 26th, 2003, 10:38 AM
There's a "nothrow" version of new that returns a NULL pointer if you want but his point is that you should never throw yourself. He believes you're only required to work with exceptions when you *have* to (e.g., you're catching a 3rd-party exception for instance). I don't know how he expects operator overloading (and chaining) to report an error but that's just one issue. In any case, this was debated in the past so you can read his record on the subject but he's completely misguided IMO. I don't believe he's fully considered the issues and that's meant without insult. As I recall for instance, he once claimed that functions don't know who's actually responsible for catching an exception which is clearly false - the exception specification tells you that a function may throw and you can catch it if you want or let it propagate up the call stack - fundamentally that's no different than manually propagating a return code, a concept he clearly advocates. Here's just one lengthy thread but I believe there are others:


Sef keep saying that I was misguided. But he failed say EXACTLY where and how I was misguided. No that is not true! I was never mis-guided. If any thing I guess you are confused yourself. The example you cited exactly shows so. It is exactly because that one has the liberty of either catch an exception or let it propagate to higher level, that it becomes unpredictable that who will catch an exception once it is thrown, or whether it will be catched at all. So am I not right in saying "functions don't know who's actually responsible for catching an exception". Why you think my claim is "clearly false"? Clearly you need to get the logic straight. I clearly don't know what's in your mind or how it works in your brain.

There are always good reasons (or rather excuses) in putting certain component into a language. There was a reason to put longjmp into C, there was also reason to put C++ exception into C++. The difference is peopel never ever abused the usage of longjmp, but people are clearly abusing C++ exceptions. In real world, the damages of C++ exceptions far exceeds its benefits.

Some people would argue that C++ exceptions are necessary to make it possible for constuctors and operators to report errors that otherwise has no mechanism to report. I say, why do you want to write a constructor or operator that can fail? If a task can be impelemented as an operator, then it should never fail. Do a = b + c ever fail? Do a = b*c ever fail? a = b/c may fail if C is zero. But do you prefer to wrape a = b/c with a try/catch, rather than simply check c before a=b/c? I would prefere the later.

a = b*c could fail to get the correct answer. But most cases you don't care, and if you care you would prefer to check the values yourself, instead of allowing the OS to throw an exception. Fortunately the OS never throws an exception if a=b*c overflows!!!

If the task could ever fail, and you care about the failure, then it should be implemented as a regular function with error return code, not as a constructor or operator.

Andreas Masur
January 26th, 2003, 01:22 PM
Well...I am aware of these discussion ("Exceptions are evil" and so on) with you as well. As Sef already pointed out it is nothing wrong with stating your opinion about a specific language item as long as you mark it as your opinion. Unfortunately you always tend to write your responses as they would be the definitive word on a topic. This is quite not true.

As it is in this case, your opinion is a different one as many others. Exception handling is a powerful mechanism if implemented correctly. I do not want to argue that it can be misused as well. But there are thousands other mechanism in C++ and even C which can be misused as well...do you complain about them as well? Your problem is simpy that you always need to argue against everything that is not your beloved ANSI C.

And regarding you constructor question....did you ever write a constructor which needed to allocate memory by using 'new'?? How would I be able to get this error outside this without using exceptions? And even by using a common mechanism called 'RAII - Resource Acquisition is Initialization'...how would indicate that the resource could not be acquired within the constructor without throwing exceptions? There are many other examples but as many of us know you even do not care if someone points out valid arguments against your statements...so I will not go further here...

Sef
January 26th, 2003, 04:07 PM
But he failed TO say EXACTLY where and how I was misguidedOk. Let's do that but I implore you to *directly* address my response for a change.

It is exactly because that one has the liberty of either catch an exception or let it propagate to higher level, that it becomes unpredictable that who will catch an exception once it is thrown, or whether it will be catched at all. So am I not right in saying "functions don't know who's actually responsible for catching an exception". Why you think my claim is "clearly false"?I have repeatedly used the term "exception specification" in these discussions. Do you know what these are? Please explain what the difference is between calling the following function using a return code or an exception. Like so (say, zero for success or an error code on failure):

int DoSomething()
{
}or this alternative which does the same thing using an exception:

void DoSomething() throw(int)
{
}You clearly advocate the first but the second is "evil". You even claim the second doesn't make it clear who is supposed to catch it. Why when they are fundamentally the *same*. The only difference is that the first returns an error using a return code, the second using an exception. The "exception specification" (do you clearly see the "throw(int)" clause at the end of the function) makes it clear to the caller that an "int" may be thrown. It's completely unambigous that the caller must be prepared to trap it. What is it about this that you don't get? How is that ambiguous compared to a return code? The same logic applies. When function 1 calls function 2, it clearly knows in both cases that failure is possible. The only difference is the mechanics at work. And in either case if the caller doesn't trap it well that's his fault. He's been warned and (for exceptions) the "std::terminate()" handler will be called (resulting in a call to "abort()" by default but you can override this with "set_terminate"). It's no less dangerous than you ignoring a return code and carrying on as if nothing happened. That can spell disaster also, frequently a lot more than just aborting the app altogether (since the app continues even after failure, resulting in potentially serious consequences). More programmers fail to do what *you* advocate (check return codes) which is potentirally much worse. At least if they ignore an exception, the app terminates by default which is frequently much safer (and again, you can even override this behaviour using "set_terminate").

Some people would argue that C++ exceptions are necessary to make it possible for constuctors and operators to report errors that otherwise has no mechanism to report. I say, why do you want to write a constructor or operator that can fail? If a task can be impelemented as an operator, then it should never fail. Do a = b + c ever fail? Do a = b*c ever fail? a = b/c may fail if C is zero. But do you prefer to wrape a = b/c with a try/catch, rather than simply check c before a=b/c? I would prefere the later.Again, this is why people get so exasperated with you. Your claims are patently false. How do I do things your way using return codes if I *can't check for failure beforehand*:

FileStream << "Writes ok"' << "sector failure writing this";You would have us not do it unless success is guaranteed which isn't even possible in some circumstances, is that right? And it matters not that using this type of syntax is frequently very convenient and often the most natural way to do things.

If the task could ever fail, and you care about the failure, then it should be implemented as a regular function with error return code, not as a constructor or operator. Because Anthony says so? What about constructors that can possibly fail. Shall we set an error flag in the constructor and hope users check it. Or should we write an "Init()" function instead and hope users call it. And in either case, then what? Have all member functions check an "Init" flag to ensure the object was properly constructed? And none of this even addresses the benefits of exceptions over return codes, not the least of which is the ability to return rich error information. Or how about the countless if/else clauses required of return codes. Let's say my top-level function invokes a series of other functions where the only failure may occur due to a disk write when I'm 20 functions deep. In your scenario there will if/else clauses pulluting the code all the way down the call stack. Every function will have a return code that gets propagated all the way to the top (complicating some functions as well, since some will then have to designate an extra out argument because the return code itself is reserved for success or failure). The top-level function finally gets notified and pops up a message for the user (and what will the message say because only a return code is available - I may want to see the exact args at the point of failure). Using exceptions however, you can set up just one try/catch in the top-level function only. Now no return code is required for trapping success or failure and each function can either be void or use the return code for some other purpose as required. Now when the bottom function encounters the error, it simply throws an exception with complete failure info if desired, unlike in the return code case (without resorting to other methods). This is then automatically trapped at the top level function, with RAII automtatically cleaning up things along the way. No checking of return codes or even other try/catch blocks are required *anywhere* except the top-level function. Very clean. Very simple.

Are there potential drawbacks to exceptions. Of course. It's not a panacea and no system is perfect. Nor have I ever claimed they should replace return codes in all situations (or at all depending on what you're doing). That's in stark contrast to your own elitist views however, where exceptions are bad and evil and should *never* be used because Anthony says so. Such asbolute assertions are clearly false and in this case completely unreasonable.

AnthonyMai
January 27th, 2003, 12:50 AM
And regarding you constructor question....did you ever write a constructor which needed to allocate memory by using 'new'?? How would I be able to get this error outside this without using exceptions? And even by using a common mechanism called 'RAII - Resource Acquisition is Initialization'...how would indicate that the resource could not be acquired within the constructor without throwing exceptions? There are many other examples but as many of us know you even do not care if someone points out valid arguments against your statements...so I will not go further here...


OK, let's talk about constructors that would fail. First, you CAN write constructors that would never fail unless catastrophy happens (like some one pulling the power plug or some memory gets over-written). You can postpone resource acquisition to later, after you have constructed the object. Further, even if the constructor can fail, you can report the error using a boolean within the object or even a static variable to indicate the error condition. There is no need to throw an exception.

Let's step back one step, let's say your constructor fails, and you do throw an exception. The question is WHO WILL catch the exception? Let's say you have a global instance of that object. Upon program loading, the constructor of that object gets called and it throws an exception. But it hasn't even started the main() function yet. So even if you have a big try/catch in the main(), you will still not be able to catch the exception!!!

I know about the RAII concept. Some one likes it. But I think it is a BAD idea. It mixes three things together: 1.Construction of an object. 2.Acquire resources that the object will be using. 3.Initialize the resource acquired. RAII attempts to do all three things at once.

The reality is you rarely want the three things to happen spontaneously. You may want to construct an object but postpone resource acquisition until when it is actually used.
You may re-acquire new resources or release old ones during the lifetime of an object, without destorying and reconstructing the object. Also, many times you do not want to initialize resource right upon acquisition, or simply is unable to initialize it yet at the moment of acquisition. So, object construction, resource acquisition, resource initialization. These three things rarely happen at the same time. RAII is an ill-formed idea that doesn't fit in the real world.

Andreas Masur
January 27th, 2003, 01:12 AM
Originally posted by AnthonyMai
OK, let's talk about constructors that would fail. First, you CAN write constructors that would never fail unless catastrophy happens (like some one pulling the power plug or some memory gets over-written). You can postpone resource acquisition to later, after you have constructed the object. Further, even if the constructor can fail, you can report the error using a boolean within the object or even a static variable to indicate the error condition. There is no need to throw an exception.

I will not reply to this one since Sef already provided more than enough information of the drawbacks of these solutions...

Originally posted by AnthonyMai
Let's step back one step, let's say your constructor fails, and you do throw an exception. The question is WHO WILL catch the exception? Let's say you have a global instance of that object. Upon program loading, the constructor of that object gets called and it throws an exception. But it hasn't even started the main() function yet. So even if you have a big try/catch in the main(), you will still not be able to catch the exception!!!

First of all...I could reply:

Let's say a constructor sets a boolean flag inside the class. The question is WHO WILL check this flag?

Second thing...global instances. There is nearly no need to define global instances in an object-oriented design...nevertheless I agree that this case would be inappropriate but that is one typical thing of your discussions...just because one case does not work - DOES NOT - mean that the whole thing is bad in general...

Originally posted by AnthonyMai
I know about the RAII concept. Some one likes it. But I think it is a BAD idea. It mixes three things together: 1.Construction of an object. 2.Acquire resources that the object will be using. 3.Initialize the resource acquired. RAII attempts to do all three things at once.

The reality is you rarely want the three things to happen spontaneously. You may want to construct an object but postpone resource acquisition until when it is actually used.
You may re-acquire new resources or release old ones during the lifetime of an object, without destorying and reconstructing the object. Also, many times you do not want to initialize resource right upon acquisition, or simply is unable to initialize it yet at the moment of acquisition. So, object construction, resource acquisition, resource initialization. These three things rarely happen at the same time. RAII is an ill-formed idea that doesn't fit in the real world.
Sorry...but this clearly shows that you did not understand the concept...

Anyway...I knew that this would happen and I will stop right here. We are already off-topic and I will not be part of another one of your endless discussions...

AnthonyMai
January 27th, 2003, 01:30 AM
Because Anthony says so? What about constructors that can possibly fail. Shall we set an error flag in the constructor and hope users check it. Or should we write an "Init()" function instead and hope users call it. And in either case, then what? Have all member functions check an "Init" flag to ensure the object was properly constructed?


It is the class auther's responsibility to properly document the usage sequence of the class and make sure the class behaves correctly when used properly. And it is the class user's responsibility to make sure it is constructed and used in the correct way, including remembering to call the Init() function.

In the case where the caller forget to call Init(), IT is a programming BUG and that we know programs with BUGs does NOT work and it does not work and it still does not work, no matter what you do. Only when the programmer identifies the problem, and put in the Init(), will it starts to work.

So I don't understand your above argument. If a program doesn't work because of a bug, it just doesn't work no matter what you do, until the correct bug is identified and fixed. Does throwing an exception help to get things working and turning around error conditions? NO!!!

If you as the user, knows that an object could fail to be constructed, or it is constructed but is not properly initialized to be used. Then it is YOUR responsibility to check to make sure the object is OK, before using it. If you don't check, and there is an error condition, then it is a bug that you should be held responsible for it.



And none of this even addresses the benefits of exceptions over return codes, not the least of which is the ability to return rich error information. Or how about the countless if/else clauses required of return codes.


The question is WHO NEEDS those rich erro information. If I am the application level code 20 layers above the code where an exception is throw because of some sort of "write back cache parity error at cylinder 2003 sector 03", or some other low level techie terminology. WHY should I need to know what it is? And how do you suppose I interpret that "rich error information"? And also how would you expect me to display such an error message, to an end user who is completely computer illiterate and have no idea what it says or whether it is English or not?

The "rich error information" argument is a very weak one. The only layer that hopefully can understand the error from a lower level code is the layer that is right above it. If you propagate it 20 levels up, then they are speaking a totally different language. This is exactly the reason why level-to-level error code return and interpretation is prefered, rather than throwing an exception all the way from low level to the topmost level.




Let's say my top-level function invokes a series of other functions where the only failure may occur due to a disk write when I'm 20 functions deep. In your scenario there will if/else clauses pulluting the code all the way down the call stack. Every function will have a return code that gets propagated all the way to the top (complicating some functions as well, since some will then have to designate an extra out argument because the return code itself is reserved for success or failure). The top-level function finally gets notified and pops up a message for the user (and what will the message say because only a return code is available - I may want to see the exact args at the point of failure). Using exceptions however, you can set up just one try/catch in the top-level function only. Now no return code is required for trapping success or failure and each function can either be void or use the return code for some other purpose as required.


If you know a function could potentially fail, then you have the responsibility of detecting and properly handling the error. Refusing to handling the error code or even make the function call a void function, and let the error that could be well handled and totally recoverable propagate to higher level and become one that is unrecoverable. I guess that is not the right thing to do in programming. My philosophy is try to handle the error and try to recover at every level, and only when you can't recover at your level will you be allowed to propagate the error one level up.

I guess that is also the HR policy of most big organizations. If you have a problem, talk to your direct supervisor first. If he can't hndle it, then you can go up one level to seek a solution. You don't skip your supervisor and directly go to the company CEO like you do in throwing an exception, right?



Now when the bottom function encounters the error, it simply throws an exception with complete failure info if desired, unlike in the return code case (without resorting to other methods). This is then automatically trapped at the top level function, with RAII automtatically cleaning up things along the way. No checking of return codes or even other try/catch blocks are required *anywhere* except the top-level function. Very clean. Very simple.


It is very clean and simple, but not very useful. If you used the level-by-level erro code return mechanism, the error condition could have been recovered and the program continues to run. But now you throw an exception to top level which can do nothing but terminate with a strange messagebox. What's the usage of the lowest level error information, to the topmost level? What can the top level do? It's useless!!!

And, are you trying to tell me that you are treating your end users as your QA testers without pay?

Gabriel Fleseriu
January 27th, 2003, 01:34 AM
Originally posted by AnthonyMai
OK, let's talk about constructors that would fail. First, you CAN write constructors that would never fail unless catastrophy happens (like some one pulling the power plug or some memory gets over-written). You can postpone resource acquisition to later, after you have constructed the object. Further, even if the constructor can fail, you can report the error using a boolean within the object or even a static variable to indicate the error condition. There is no need to throw an exception.

No. If the ctor fails the object is not created, yet. It does not begin its lifetime until until a successful ctor termination. You may want to read Herb Sutter's "Exceptional C++" and "More Exceptional C++" to learn about object lifetime and failing ctors.

Let's step back one step, let's say your constructor fails, and you do throw an exception. The question is WHO WILL catch the exception? Let's say you have a global instance of that object. Upon program loading, the constructor of that object gets called and it throws an exception. But it hasn't even started the main() function yet. So even if you have a big try/catch in the main(), you will still not be able to catch the exception!!!

If your ptogram is not able to construct a global object then it is very likely not to work at all -- exception caught or not. So a call to exit() is the right thing to do. Don't use a global object if you want to be able to catch exceptions from its ctor.

I know about the RAII concept. Some one likes it. But I think it is a BAD idea. It mixes three things together: 1.Construction of an object. 2.Acquire resources that the object will be using. 3.Initialize the resource acquired. RAII attempts to do all three things at once.

The reality is you rarely want the three things to happen spontaneously. You may want to construct an object but postpone resource acquisition until when it is actually used.
You may re-acquire new resources or release old ones during the lifetime of an object, without destorying and reconstructing the object. Also, many times you do not want to initialize resource right upon acquisition, or simply is unable to initialize it yet at the moment of acquisition. So, object construction, resource acquisition, resource initialization. These three things rarely happen at the same time. RAII is an ill-formed idea that doesn't fit in the real world.

RAII is in most cases not avoidable if you want to write code that suffices the strong exception specification -- that is a commit or rollback specification. Even for the weak exception spec, RAII can massively help leaving the program in a consistent state in case of an exception.

As this tends to become an "Anthony against the rest of the world" discussion (again!), I sugest we stop here.

Andreas Masur
January 27th, 2003, 03:27 AM
Originally posted by AnthonyMai
If you as the user, knows that an object could fail to be constructed, or it is constructed but is not properly initialized to be used. Then it is YOUR responsibility to check to make sure the object is OK, before using it. If you don't check, and there is an error condition, then it is a bug that you should be held responsible for it.
And this actually is exactly one of the arguments for using exceptions for constructors... :cool:

Sef
January 27th, 2003, 09:59 AM
If you as the user, knows that an object could fail to be constructed, or it is constructed but is not properly initialized to be used. Then it is YOUR responsibility to check to make sure the object is OK, before using it. If you don't check, and there is an error condition, then it is a bug that you should be held responsible for it.You're completely missing the point that doing things this way is possible but has severe drawbacks compared to exceptions (discussed ad nauseam already). Furthermore, please explain how to handle a copy constructor and copy assignment operator that can fail. Do you check for an error condition after each assignment for instance? And how do you handle this without a lot of ugly overhead. And what about when it's implicitly called by the compiler. Or if it's being used with a standard library collection, where objects *must* be copy constructible, then what? Since you yourself once claimed that you've "NEVER thrown any exception in my career", then I guess you've never written a class that manages resources or can otherwise fail. If you have then either you're privatizing your copy constructor and copy assignment operator in all such cases (right), or you're having each member function check to see if the class was properly initialized and/or assigned (brutal and if so, then what do you do about it if the object is being managed by a collection), or finally, you yourself are writing code that can fail but aren't doing anything about it (probably). So I guess that "you should be held responsible for it".

Anthony, the reality is that your arguments are incredibly weak and mostly non-existent. In fact, they frequently demonstrate that you either don't understand the issues or you're just incredibly stubborn and can't acknowledge the truth (a mixture of both actually). You don't even address some very important issues like "exception specifications" which completely obliterates your argument that nobody knows who will be catching an exception. I don't believe you were even aware of these before but now you are so you're caught in your own ignorance of the subject and won't even address it. You also point out trivial examples of when something won't work and then claim the whole thing is garbage and should never be used altogether (globals are your strongest argument? come on). And then you continously rant that top-level functions won't know what to do with an error that occurred way down the call stack when all they want to do is *report* it (say, using a virtual "CreateErrorMsg()" function that generates a string from the details). Rich error information may just consist of a string in fact. And for *most* apps, a critical error need only be dealt with by reporting and/or logging it so there's no need to try to recover at the point where it occurs (nor is it possible in many cases). As for the message itself, who are you to say how technical it must be or who will even be looking at it. It can be technical if it's for technical eyes only, or for non-technical users, can consist of a user-friendly message only. The technical details themselves can then be logged somewhere and the proper people can later diagnose it. Why do you keep arguing such asinine points. There is no point debating this at all anymore. You're incapable of dealing with facts.

AnthonyMai
January 27th, 2003, 02:54 PM
I said:

If you as the user, knows that an object could fail to be constructed, or it is constructed but is not properly initialized to be used. Then it is YOUR responsibility to check to make sure the object is OK, before using it. If you don't check, and there is an error condition, then it is a bug that you should be held responsible for it.


And Sef said:

You're completely missing the point that doing things this way is possible but has severe drawbacks compared to exceptions (discussed ad nauseam already).


What severe drawback? Is it harder to check one single error return code versus catch one single exception? I don't think so.
Given a choice, do you prefer to write 100 error code checking, or would you rather write 100 try/catch instead?

OK, maybe you don't need to replace each and every return code check with a try/catch. Maybe you can use just one try/catch in the main() program? But it is NOT the same thing. Where when I check all 100 return code, I am handling all error conditions properly and I can always recover from any error that is recoverable, and exit gracefully when I can't. But when you use exception, you could be forced to terminate the whole program when an error that could have been recoverable triggers an exception.

Better yet, just write no try/catch at all. It's easier, you thrown an exception and the OS will catch it for you, right? It makes no difference whether you terminate on your own or the OS terminates you, when you can't recover.

Look, I know having to handle all error conditions at all levels is tedious. But there is no way around it. Either you handle it right at the spot, or you let the top level or even the OS to handle your error. The difference is when I do it in low level I can handle it nicely and recover gracefully, when it escalate to the top level, you have no choice but terminate the whole thing.



Furthermore, please explain how to handle a copy constructor and copy assignment operator that can fail. Do you check for an error condition after each assignment for instance? And how do you handle this without a lot of ugly overhead. And what about when it's implicitly called by the compiler. Or if it's being used with a standard library collection, where objects *must* be copy constructible, then what?


Here is my answer: Just do NOT write a copy constructor, copy assignment operator, or an operator, or a void function, or something else that does not have a way of telling its caller about the error condition, ever, at all. Don't do it! If you know a function could fail, then don't make it a void function. If you know an operation can fail, don't make it an operator, implement it as a regular function with an error return code.

That doesn't mean you can never write a copy constructor or operator. In most cases, you can probably be pretty sure it simply will never fail. For example, copying an integer object to another integer object, will it ever fail?

In other cases it may fail, but the odd is too small, or it is not important whether it fail or not, then no body says you still need the overhead to check the error condition.

You WILL need the "ugly overhead" to check error conditions, if it is a case where it may fail, and it is important to handle failure properly. In such case, you HAVE to handle it. Either you handle it right at the spot where you have the best knowledge to handle it gracefully, or you let the top level or even the OS to handle it in a not-so-graceful way, i.e., forceful termination of the program.

I would prefer to have "ugly overhead".

Here is a question for you, with a, b, c all integers, calculate:
a = b * c;
You know it could fail to get correct result some times (overflow). How do you prefer to handle error condition in this case?

1. It should throw an exception, and I will write a try/catch around every code line like a = b*c;

2.It should throw an exception and I will let the top level code catch it and terminate the program.

3.It's just one none-critical error and I will let the error pass without doing anything.

4.It's a critical error and I will check the value of b and c before hand to make sure it doesn't happen.

Would you rather prefer to see a = b*c throws an exception? Or would you rather prefere 3 and 4 above?



Since you yourself once claimed that you've "NEVER thrown any exception in my career", then I guess you've never written a class that manages resources or can otherwise fail. If you have then either you're privatizing your copy constructor and copy assignment operator in all such cases (right), or you're having each member function check to see if the class was properly initialized and/or assigned (brutal and if so, then what do you do about it if the object is being managed by a collection), or finally, you yourself are writing code that can fail but aren't doing anything about it (probably). So I guess that "you should be held responsible for it".


I explained it already. I have never thrown a single exception in my programming career, though for numerous times I was forced to write code to catch exceptions thrown by others, which I hate.
And I do have to write classes that needs to handle all sorts of error conditions all the time, like a class that fails to open a socket, a class that fails to parse a string due to the corrupted format, a class that fails to open an audio device because it was used already, etc. etc. But I never have to throw an exception, ever!

If you always put tasks that could fail into a regular function which returns error conditions, and always check error conditions where ever appropriate, then I don't see a need for throwing exceptions.

To sum up, just NEVER EVER write fail-able tasks into something where it is unable to report the error. Never write a constructor, operator, copy constructor or void function in a way that can fail. Use a regular function instead, and separate the fail-able portion of the constructor into a separate initialization function.

AnthonyMai
January 27th, 2003, 02:59 PM
Sef:
Just one quick easy question for you. If your project gives an "unhandled exception error". Who, within your team of 100+ person who work at 20 different coding levels, would you be talking to, regarding the exception that is thrown but no one catches it? Who do you blame?

KevinHall
January 27th, 2003, 03:39 PM
Ok, I think we all know where eachother stand now.... Let's remember, this is a forum, not a boxing ring!

Bassman
January 27th, 2003, 03:54 PM
Look, I know having to handle all error conditions at all levels is tedious. But there is no way around it.

Yeah there is - you can use C++ exceptions.

There is no universally accepted rule to never use exceptions.

There is no universally accepted rule to always use exceptions.

A good programmer evaluates the tools at hand (exceptions, STL, etc.) within the context of the problem they wish to solve, and uses those tools accordingly.

Regards,
Bassman

P.S.

Who, within your team of 100+ person who work at 20 different coding levels, would you be talking to, regarding the exception that is thrown but no one catches it? Who do you blame?

Tvor. (Simpsons reference) :p

TheCPUWizard
January 27th, 2003, 04:34 PM
Without getting into the good vs. bad of exceptions directly...

There is one key difference between using a return value for errors and throwing an exception..

When using a return value is it possible for the user of the code to ignore the value and continue processing without taking any corrective action

Exceptions force the user to address address the situation explicitly, or the program will exit (the OS catching the exception).

Therefore I believe that the decision to use exceptions or return codes is highly dependant on what you require of users of the code (even if it is just yourself!).

About 18 months ago, as part of a research project, I did a (automated) code crawl through one of the largest open source sites on the net. Scanning just for WIN32 API calls, I monitored the number of times that the return values were actually checked. The result was that less than 15% of the system calls had their return values checked.

This test was simply done by looking to see if the call was within a conditional statement or had its return value assigned to a variable. No further testing was done to see if the program actually took any action on the value.

At my firm, we have taken the opposite approach and wrapped all Win32API calls (and most other 3rd party libraries) inside of tight in-line classes that convert error codes to exceptions. This forces our users (typically one of our own developers) to address the issue in an appropriate fashion. A nice side effect was that it provided a convient way to inject errors for the QA department...

Paul McKenzie
January 27th, 2003, 04:44 PM
If you know a function could fail, then don't make it a void function. If you know an operation can fail, don't make it an operator, implement it as a regular function with an error return code.Which goes against practically every C++ math, matrix, and linear algebra library that has ever been created. Examples (and these are just some examples -- I could have gone on and on, but there is a character limit to posts on CodeGuru):

http://www.techsoftpl.com/matrix/
http://www.netwood.net/~edwin/svmtl/#proposal
http://www.osl.iu.edu/research/mtl/
http://www.robertnz.net/nm10.htm
http://gama.fsv.cvut.cz/~cepek/gmatvec-doc/html/

And just for the heck of it, your favorite -- templates:

http://www.oonumerics.org/blitz/manual/

Now you show me a C++ math library that doesn't use exception handling or overloaded operators. Whatever it is, I can bet double or nothing it started out as a 'C' library and the author(s) wanted to be "cool" and created a C++ class, thinking they were "in with the 90's and OOP programming", but the class really does nothing special "C++"-wise.

Let's cut to the chase and get to the bottom line -- it's obvious to anyone here that you are comfortable with 'C' and 'C' techniques (even if they violate the ANSI C++ standard) to solving problems. At least admit this, so that next time, we all know where you're coming from.

Regards,

Paul McKenzie

AnthonyMai
January 27th, 2003, 06:14 PM
quote:
--------------------------------------------------------------------------------
If you know a function could fail, then don't make it a void function. If you know an operation can fail, don't make it an operator, implement it as a regular function with an error return code.
--------------------------------------------------------------------------------

Which goes against practically every C++ math, matrix, and linear algebra library that has ever been created. Examples (and these are just some examples -- I could have gone on and on, but there is a character limit to posts on CodeGuru):

...

And just for the heck of it, your favorite -- templates:

http://www.oonumerics.org/blitz/manual/

Now you show me a C++ math library that doesn't use exception handling or overloaded operators. Whatever it is, I can bet double or nothing it started out as a 'C' library and the author(s) wanted to be "cool" and created a C++ class, thinking they were "in with the 90's and OOP programming", but the class really does nothing special "C++"-wise.



Did I ever say "NEVER use operators" or any thing to that effect? I did NOT. All I am saying is if it is an operator, it should never fail. If it should ever possibly fail, then it should not be an operator, but be implemented as regular function instead.

Now, about math libraries. From a pure mathematics point of view, virtually ALL mathematics problems occured in the engineering world ARE ALWAYS computable and can be carried out WITHOUT an error. You take a 3x3 matrix and multiply it by another 3x3 matrix, you always gets a 3x3 matrix back. Can you give me one example, mathematically, that a 3x3 matrix multiplied by a 3x3 matrix does not yield a 3x3 matrix?

Well in the engineering world, overflow is possible due to limited word length. Still, such anormality would be handled by a CPU generated exception, NOT a C++ exception. Do you ever see a piece of C++ code that checks the value of a and b, and throw an exception if a and b is too big, before carrying out the calculation c = a*b? You don't do that.

Personally I have no objection to usage of operators at all. In one of my projects I used operators extensively to carry out modula mathematics in a piece of encryption related code. Did any of my operator throw an exception? No. Could error ever occur in one of my operators? No. It's pure math so there is not a possibility at all that any of my operator could ever yield an error condition.

There are certain things in the computing world that is virtually guaranteed to always work and never fail. You can always XOR two numbers without checking to make sure it works. You can always add two numbers without worrying about a CPU exception being thrown. You can always multiply two prime numbers of 512 bits and expect the end result to be no more than 1024 bits without error. It is because we have certain elements in computer code that we know always guarantee to work, that programming becomes possible. If that is not true, if every single line of computer code could potentially trigger an exception, including code that throw and catch exceptions, then there is no way of writting computer programs that would work.

And math functions happen to be one of such things.

Bassman
January 27th, 2003, 06:40 PM
There are certain things in the computing world that is virtually guaranteed to always work and never fail. ...
And math functions happen to be one of such things.


What is the square root of negative five?

What is log(-1)?

What is tan(90 degrees)?

... were you joking?

Regards,
Bassman

stober
January 27th, 2003, 06:44 PM
Ever hear of divide by zero errors?

AnthonyMai
January 27th, 2003, 06:48 PM
There is one key difference between using a return value for errors and throwing an exception..

When using a return value is it possible for the user of the code to ignore the value and continue processing without taking any corrective action

Exceptions force the user to address address the situation explicitly, or the program will exit (the OS catching the exception).


You are wrong. It is exactly the opposite. If the function I call throws an exception and I did not catch it, you can't blame me. I can turn around and blame the top level programmer for not catch all exceptions thrown 20 levels down under. On the other hand, if the function I call returns an error code, the responsibility of handling the error squarely lays on my shoulder. If I don't handle the error where I should. I can not turn around
and blame Joe.

It's one of the problem with C++ exceptions: The standard leaves it OPTIONAL for any of the upper level code to either catch it or let it propagate further up. So who carries the responsibility of handling the error becomes unclear.



Therefore I believe that the decision to use exceptions or return codes is highly dependant on what you require of users of the code (even if it is just yourself!).

About 18 months ago, as part of a research project, I did a (automated) code crawl through one of the largest open source sites on the net. Scanning just for WIN32 API calls, I monitored the number of times that the return values were actually checked. The result was that less than 15% of the system calls had their return values checked.


If you are to do a statistics of what percentage of code would try to catch an exception right where it occurs, instead of let it propagate several levels up, you would find that the ratio is far below 15%.

Now to defend the 15% figure, while function implementers should ALWAYS return error code where ever failures are possible, function caller are NOT required to always check for errors. In lots of cases, they don't need to check because when operations of previous code lines succeed, then they know by logic that the next function call will surely succeed. In other cases, the error is a none-critical one and can be safely ignored. In still other cases, there is no need to handle the error at all, for example I am exiting the program and I try to release some memory but it fails. What can I do? Hang there indefinitely, or just ignore it and quit anyway?

Considering all those scenaries where error checking is deemed un-necessary, I think the 15% figure is pretty good.



This test was simply done by looking to see if the call was within a conditional statement or had its return value assigned to a variable. No further testing was done to see if the program actually took any action on the value.

At my firm, we have taken the opposite approach and wrapped all Win32API calls (and most other 3rd party libraries) inside of tight in-line classes that convert error codes to exceptions. This forces our users (typically one of our own developers) to address the issue in an appropriate fashion. A nice side effect was that it provided a convient way to inject errors for the QA department...


I thought ASSERT is the tool for debugging and a finished product should not contain stuff that benefits only the debugging. It is just un-ethical to turn the end users machine into your own QA test machine. And end users normally doesn't co-operate.

Also keep in mind, programs that contain exception handling code are generally CONSIDERABLY SLOWER than those that doesn't, due to the extra book-keeping for maintaining exception handling, at each and every function call, even if the exceptions only happen one in a billion.

AnthonyMai
January 27th, 2003, 07:05 PM
Stober: Ever hear of divide by zero errors?


Divided by zero is a CPU exception. It is NOT a C++ exception. You can not generate a divided by zero C++ exception. We are talking about C++ exception here that you manually generate by "throw".


What is the square root of negative five?

What is log(-1)?

What is tan(90 degrees)?

... were you joking?


Mathematically, all these calculation will give you a valid result.

Computerwise, None of these functions throws a C++ exception. Even if they want to throw a C++ exception they don't know how, since they are C functions. So they are irrelevant to our discussion about C++ exceptions.

BTW, these functions do return something that indicates invalid result. Check it out.

scorpicorn
January 27th, 2003, 07:07 PM
I like to thank everyone who replied. You have provided really valuable information and insights with regard to the topic on exception handling.

I didn't mean to start an argument here. Never expect this thread to explode into such a furious debate as well. If anyone is seriously upset about the whole discussion, I'm truly apologetic.

Thanks, once again.

Bassman
January 27th, 2003, 07:20 PM
If you are to do a statistics of what percentage of code would try to catch an exception right where it occurs, instead of let it propagate several levels up, you would find that the ratio is far below 15%.


I repeat again, and again, and you always ignore me (not that i'm surprised), stop making stuff up and posting it as fact.

I refuse to argue anything else, because, frankly, you're likely to lie again and again. Which makes meaningful discourse with you an impossibility.

Regards,
Bassman

Paul McKenzie
January 27th, 2003, 07:31 PM
Folks, Mai doesn't even believe in technical support.

Here is the thread:

http://www.codeguru.com/forum/showthread.php?s=&threadid=214616&perpage=20&highlight=log&pagenumber=2

According to Mai, technical support is not needed(!!), and he gives the extremes of 2 failures out of a million, and 1 out of 10 failures (as if a large software product written for today's environments falls on either end of this scale).

Note the same thinking from his last message:
And, are you trying to tell me that you are treating your end users as your QA testers without pay?This is an absolute inanity. Large software products are QA tested very thouroughly, and can still fail, but at a very small rate. Not one in 1 million, but the rate is much smaller than the fictitious "1 out of 10" strawman you brought up. For those rare failures, exception handling is well worth it, instead of giving no technical support, no error logging, and just shrug your shoulders, claiming that it is a "user error" because you write "correct code.

And are you stating that all of those C++ math libraries are done by inferior programmers who don't see the great and wise ways of returning error codes? Why do all of the authors of the libraries listed use exceptions? Is this another "Stroustrup and all of the ANSI committee is wrong" moment from you? You really do like tilting at windmills...

Regards,

Paul McKenzie

Sef
January 27th, 2003, 07:48 PM
You are wrong. It is exactly the opposite. If the function I call throws an exception and I did not catch it, you can't blame me.Of course you'll be blamed(!) because the very first function that you call will have an "exception specification" (remember those) explicitly telling you that it may throw something. It matters not where the exception comes from (20 functions deep or wherever). That's no different than the first function stating that it may return an error code which you'll be blamed for if ignored according to your own diatribes (even though the error code originated from 20 functions deep). Honestly!

It's one of the problem with C++ exceptions: The standard leaves it OPTIONAL for any of the upper level code to either catch it or let it propagate further up. So who carries the responsibility of handling the error becomes unclear.Read up on EXCEPTION SPECIFICATIONS!!!. A return code is actually more optional than an exception is (and potentially more dangerous if ignored since an ignored exception will terminate by default).

TheCPUWizard
January 27th, 2003, 07:50 PM
First I would like to clarify a previous post of mine:

A nice side effect was that it provided a convient way to inject errors for the QA department...

Taken in context, I was NOT in any way suggesting that our customers are the "unpayed QA department". Rather having the system calls inside in-line wrappers (which rarely produce ANY performance impact over checking the result code) provides a method for our well-paid (at least that is the opinion of management) in house QA despartment to inject errors.

It can be very difficult to truely inject all of the possible failures that can result from a system call. Even inducing the more common ones is difficult.

By having the code inside a class wrapper, the QA department is able to replace our system calls with their own wrapper class that induces fixed or quasi-random errors. Typical uses of this are sporatic memory allocation failures, socket communication failures, and thread/process deadlocking failures.

Again this was a side effect of wrapping the system calls that has allowed us to simulate problems that could occur in the real world where truely inducing these faults withing the OS code would be difficult or impossible to do (especially on a repatable basis).

TheCPUWizard
January 27th, 2003, 08:22 PM
1) There are many classes available that will convert an SEH into a C++ exception. This allows items such as math overflows to be converted into C++ exceptions and processed accordingly. Nearly every well written program that uses exceptions installs one of these handlers.


2) Using exceptions does guarentee that the user will process the exception or the execution will leave that users code and return to the next level. This is the entire point. Consider the following code fragment.


int f(CmyClass *&ptr)
{
if (everythingOK)
{
ptr = m_PTR;
return 0; // success
}
else
{
return 123; // some error code
}
}


// now the user code.

CmyClass *p = &someValidObject;
int rc = f(p)
p->SomeMethod()



In this scenario (i.e. not checking the return value of f()) it is impossible to determine if the original object (someValidObject) or the (m_PTR) object is being invoked.

On the other hand, if f() had thrown an exception (instead or returning 123), it would be certain that the function had succeeded.

If the user whated processing to continue regardless of the functioning of f(), then explicit operations (a catch block) would have been required.

Exceptions are much more deterministic than return codes. With execptions it is the same as in the military, if you dont handle it, I will tak it to your commanding officer, and up the chain of command until the president (operating system) if necessary.

stober
January 27th, 2003, 08:35 PM
Maybe it is just not a good example, but I'd much rather do as follows than use an exception:


// now the user code.

CmyClass *p = &someValidObject;
int rc = f(p)
if(rc == 0)
p->SomeMethod()

TheCPUWizard
January 27th, 2003, 08:47 PM
Granter the sample code is (overly??) simple. The point is that as the author of f() I can not guarantee that you are going to check the return value. By throwing an exception I can be 100% certain that you are going to be explicitly aware of it (although I can not be sure you will deal with it "properly") or you will no longer have a chance to proceed.

The even bigger issue occurs when a routine which can not possibly generate and error today is modified by its author so that it can generate an error (or a routine which could previously only generate error "A" can now also generate error "B").

It is reasonible to expect EVERY client that uses this routine to be modified in a timely manner?

If you have used a routine that returns void (i.e. it can not generate an error condifiton) in a few hundred locations in a few dozen programs, would you be willing to stake any significant wager on you finding every single one of these and not missing a single one?

AnthonyMai
January 27th, 2003, 11:48 PM
Exceptions are much more deterministic than return codes. With execptions it is the same as in the military, if you dont handle it, I will tak it to your commanding officer, and up the chain of command until the president (operating system) if necessary.

The military command system is a good analogy. The way exceptions are handled are exactly you said, basically a soldier at the lowest level could potentially go all the way to the president for something trivial. And the president has no idea what's the problem is and what the soldier wants, and can only simply throw the guy out and ask him never to bother him again since the president has a lot of important things to do.

On the contrary, the return code system is much more rational. You only directly report to your direct supervisor. You never gets to the president directly. Once you report it to your direct boss your duty is done, then it is up to your supervisor to decide whether to dismiss it, handle it himself, or report one level up and let the upper level supervisor to handle it. Isn't it a better system?


The even bigger issue occurs when a routine which can not possibly generate and error today is modified by its author so that it can generate an error (or a routine which could previously only generate error "A" can now also generate error "B").


If a function has changed its interface, then yes, it is time to go through the whole code base and exam each and every instance where it is used and make sure it still makes sense. You have to do it. And you are not allowed miss even one single spot.
A it takes to generate a computer bug is one single spot where one function is mis-used. Is that an unreasonable requirement? I don't think so.


It is reasonible to expect EVERY client that uses this routine to be modified in a timely manner?


It definitely is! Every single client needs to use the routine MUST use it CORRECTLY. If you make 100 calls and 99 calls are correct, that is not good enough. One mis-use out of a million and it is a bug nevertheless. If you double checked every thing but still missed the bug, that is one thing. If you do not even bother to go through it even just once and let the bug slip through, that is another.

As for whether you can do it in a timely manner, it's all up to the original decision of benefit and cost of changing the function interface, and whether or not your time and budget allow you to get it done in a time frame acceptable to you.


If you have used a routine that returns void (i.e. it can not generate an error condifiton) in a few hundred locations in a few dozen programs, would you be willing to stake any significant wager on you finding every single one of these and not missing a single one?


Is it really so hard to come up with an exhaust list where the said function is referenced? Are you willing to bet money on it being difficult? I don't think so at all. Do a global search! Better yet, change the function name slightly. So you will NOT miss a single location. If you miss, the compiler WILL remind you with an un-resolved external error. Actually I think it is a good idea to ALWAYS change the function name some what, when the interface changes. This makes sure you will go through every instance where it is referenced and make appropriate changes.

galathaea
January 28th, 2003, 12:02 AM
Of course, with proper application design, you build an exception handling pattern that does not need to infiltrate all one's code, is perfectly scalable, and can smoothly recover from errors. It is a normal part of your object design to map exception flow and handle at appropriate junctures. Of course, you can put some form of invalid default parameter check in most places and maybe fix up everything else in some way to deal with incomplete objects, but now you have built your own non standard exception handling method that is much more difficult to maintain or scale.

And it is really difficult to see how one deals with the generic programming problem of returning a generic type by value or reference, as there is no generic default error return (see boost::any or Volker Simonis' chameleon objects). It is possible to structure things so that you do not have a generic return type, but as above you are propagating incomplete types, and you must separate the error indicator from the object.

And, of course, you need to keep track of which objects are invalid somewhere if you wish for cleanup to even be possible (and is this tracking always possible?). Exception does the clean up in a well defined manner.

KevinHall
January 28th, 2003, 02:54 AM
I once had to work on a library that some of my company's customers required be written in C. Some of the most fundamental, system level calls were buried 6 function calls down from the exposed library interface. PLEASE NOTE: this was a very well written and tested library -- our customers still sing the praises of it years laters! But, being written in C, we could not use exceptions. Also, we needed to pass all error codes back up to the user (via long return values). This is one example of what our code ended up looking like in each of our functions:


/* Can't return the variable directly b/c of error code */
long GetSomeVariable(SomeVariable* someVar)
{
long result = OK; /* enumerated in header file */

/* Some trace and assert statements here */

if (someVar == NULL)
{
result = INVALID_PARAM; /* enumerated in header file */
}
if (result == OK)
{
result = MoreFundamentalCall1();
}
if (result == OK)
{
result = MoreFundamentalCall2();
}
if (result == OK)
{
int index;
for (index=0; index<something; ++index)
{
result = MoreFundamentalCall3();
if (result != OK)
{
break;
}
}
}
if (result == OK)
{
result = MoreFundamentalCall4();
}
/* etc, etc, etc... */

/* More trace statements here */

return result;
}


In C++, with exceptions, you could just write:


// Can return the variable directly
SomeVariable GetSomeVariable() throw OurLibException
{
SomeVariable returnValue;

// Some trace and assert statements here

try
{
int index;

MoreFundamentalCall1();
MoreFundamentalCall2();
for (index=0; index<something; ++index)
{
MoreFundamentalCall3();
}
result = MoreFundamentalCall4();

// etc, etc, etc...
}
catch (OurLibException& e)
{
// Trace statements concerning exception;

throw e; // re-throw exception
}

// More trace statements here

return returnValue;
}


Now this is a short example. I have discovered our C code would be the ~ 1/3 the size if exceptions were used. I have also discovered:
* Code maintenance takes about twice as long b/c of having to having to write all the "if (result == OK)"'s
* Debugging code also takes about three times as long b/c of (a) all the if statements, and (b) b/c C++ exceptions can contain much more information (reason exception happened, file and line where it happened, state information, text message, ...) where a long just can't (granted we could have passed back a large data structure all the way to the top, but that would have made our C code very innefficient!)

As far as technical support goes, when our customers have the information from the C++ exceptions, they can say "hey, here's where, why, and the state of my system when I got this error, what's going on?" as opposed to "hey I got code 0x402 which translates to 'this object could not ...' -- can you please look into this for me?" I can testify here that figuring out if the customer made a mistake or if we have a bug is much, much easier with the extra information provided by the exceptions.

- Kevin

P.S. Global variables in C just did not work for storing the extra information in C b/c our library was a multithreaded library, and we could not afford to possibly lose error information from one thread when an error from another thread would overwrite it.

TheCPUWizard
January 28th, 2003, 07:48 AM
Galathaea, Kevin. Thanks for good posts.

The point that people such as Anthony keep missing is that when the author of the "function" and the user of said function are different people (possibly at different companies), there is no possible way for the author to verify that the user is going to check the return code.

Even when the person is the same, mistakes can and will happen. Ideas such as doing a search do not really work. Using Kevin's example code consider the following:


/* Can't return the variable directly b/c of error code */
long GetSomeVariable(SomeVariable* someVar)
{
long result = OK; /* enumerated in header file */

/* Some trace and assert statements here */

if (someVar == NULL)
{
result = INVALID_PARAM; /* enumerated in header file */
}
if (result == OK)
{
result = MoreFundamentalCall1();
}
if (result == OK)
{
result = MoreFundamentalCall2();
}
if (result == OK)
{
int index;
for (index=0; index<something; ++index)
{
result = MoreFundamentalCall3();
if (result != OK)
{
break;
}
}
}

// BUG INDUCED AT THIS LEVEL!
//if (result == OK)

{
result = MoreFundamentalCall4();
}
/* etc, etc, etc... */

/* More trace statements here */

return result;
}


I would really like to see a concrete example of a search that would detect the fact that an error in MoreFundamentalCall1 would still result in a bad call to #4

AnthonyMai
January 28th, 2003, 10:12 AM
And, of course, you need to keep track of which objects are invalid somewhere if you wish for cleanup to even be possible (and is this tracking always possible?). Exception does the clean up in a well defined manner.


It's exactly the opposite. It is well know that by using exceptions you may have problem clean up allocated resources. For example if you within a function call, you open up a device, initialize it, use it, then clean it up, close it, release it. If you follow the normal flow of how things happen every thing works fine. But if you throw an exception in the middle which was catched a few layers up, then all the cleanup code have been skipped, causing resource leak. The only way of avoiding such thing is you NEVER acquire/release resources except for when you do it in the constructor/destructor.

So usage of exceptions leaks to the so called RAII concept. And the whole thing eventually leads to such extreme code style that basically every thing is done in constructors and destructors, and
the only functions exist are void functions, and the only way a function reports an error is through exceptions. The rational is you never ever need to check for error return code and all errors are handled by exception. So there is no need for any function that returns an error code. But to avoid resource leak, virtually every thing must be done in constructors and destructors.

I have seem such code. It's terrible. It's completely unreadable.

KevinHall
January 28th, 2003, 10:28 AM
Just out of curiosity here.... What type of companies do you guys work for? What type of projects do you guys work on? Do you write complete solutions for your company/customers or do you write libraries for others to use? I think this will enlighten me (somewhat anyway) as to why people have the opinions they do.

I'm particularly interested in what Galathaea, Anthony Mai, Paul McKenzie, and Sef do. (Of coarse I'd be interested in what the rest of you do too...)

For me, I work in a company that does embeded robitic controls and along with our hardware, we have to supply software libraries. It's pretty exciting getting to interact all the time with the "real world" and dealing with multiple processors, multiple threads, the occasional RTOS, and situations like: "Someone just ran over the control wiring with a forklift, now bring whatever you can to a controlled stop, save important information, and report a meaningful error back to the master computer."

- Kevin

KevinHall
January 28th, 2003, 10:28 AM
Just out of curiosity here.... What type of companies do you guys work for? What type of projects do you guys work on? Do you write complete solutions for your company/customers or do you write libraries for others to use? I think this will enlighten me (somewhat anyway) as to why people have the opinions they do.

I'm particularly interested in what Galathaea, Anthony Mai, Paul McKenzie, and Sef do. (Of coarse I'd be interested in what the rest of you do too...)

For me, I work in a company that does embeded robitic controls and along with our hardware, we have to supply software libraries. It's pretty exciting getting to interact all the time with the "real world" and dealing with multiple processors, multiple threads, the occasional RTOS, and situations like: "Someone just ran over the control wiring with a forklift, now bring whatever you can to a controlled stop, save important information, and report a meaningful error back to master computer."

- Kevin

KevinHall
January 28th, 2003, 10:33 AM
And oh yes, CPUWizard, I have already seen your buisness site.... What is the most interesting project you worked on?

AnthonyMai
January 28th, 2003, 10:35 AM
I would really like to see a concrete example of a search that would detect the fact that an error in MoreFundamentalCall1 would still result in a bad call to #4


In your example, if you a function's return code need to be checked, it is easy to do a global search to find out all 100 instances where the function is called, and quickly glance them one by one to make sure they are all correctly checked. It is easy because the error return check is always next to where the function call is made.

On the contrary, if a function throws an exception, how do you know the exception is caught. And how do you know it is caught at the appropriate level, instead of un-necessarily propagated to the topmost level or even the OS when it could have been handled at a much lower level?

You would have to look at each instance of the function call. Figure out the whole calling stack for each one. And check each level in the call stack, to see if there is a try/catch that wrapes the call, and further, you need to exam the type of exceptions that each catch catches, to see if it is the match type of exception.

To carry out such a task is virtually impossible.

That's why a greater than half of all software bugs in the real world are associated with "unhandled exceptions".

Sef
January 28th, 2003, 11:58 AM
Originally posted by KevinHall
Just out of curiosity here.... What type of companies do you guys work for? What type of projects do you guys work on? Do you write complete solutions for your company/customers or do you write libraries for others to use? I think this will enlighten me (somewhat anyway) as to why people have the opinions they do.[/i]I've been in the field for almost 20 years mostly working in C and C++. I contracted for about a dozen different companies from the late 80s until 2000 and then left to work on my own million dollar idea which I'm still at. Of course none of this has anything to do with exceptions which are a language construct that usually has little to do with the nature of your company (though the type of app you write may influence whether you use them or not).

<< This posting has been edited by the admin. Negative comments towards others are in violation of this site's usage>>


<<REMOVED>>
If someone writes a top-level function that invokes another function for instance, then the latter function can either report an error using a return code or an exception (as far as this discussion is concerned anyway). In either case however, the caller knows that they have to trap an error. They know that because the documentation for the function tells you that it either returns a failure code or it throws an exception (in the latter case the "exception specification" on the function prototype will tell you that). It matters not that the function you're calling is invoking yet another function where an error can be propagated from 20 functions deep using a return code or an exception. From the caller's perspective they only know that the function can generate an error and must trap it. They have no clue without reading the code that the function invokes many other functions and the error can originate from way down the call stack. They may not even have the code nor should they have to read it if they're just clients of the code. Only usage documentation is required and that documentation shows either a return code or an expection specification (again, the prototype will show either). So why does <<anyone>> persist in arguing that nobody knows who will trap it nor is <<anyone>> to blame if the guy 20 functions deep does throw an exception. He can clearly see that the function he himself is calling may fail because the exception specification says so. It's no different than testing a return code which he would presumably do and would be blamed for if he didn't. He doesn't seem to understand that it works the same way. If all functions down the hierarchy can fail then all will show either a return code in their signature *or* an exception specification. There is no difference between the two methods <<removed>> if the lower level function wants to handle the error itself then it can easily do so but its exception specification will now show "throw()" instead (meaning it doesn't throw any exceptions). That's the same as changing a function based on return codes to "void" meaning no error is returned. The return code on all upper-level functions may then also show "void" as well if necesary or "throw()" when using exceptions. In fact, the original function being called at the top may now show "void" or "throw()". <<Removed>>

AnthonyMai
January 28th, 2003, 12:58 PM
He continues to argue for instance that nobody knows who will catch an exception in spite of my repeated references to "exception specifications". If someone writes a top-level function that invokes another function for instance, then the latter function can either report an error using a return code or an exception (as far as this discussion is concerned anyway). In either case however, the caller knows that they have to trap an error. They know that because the documentation for the function tells you that it either returns a failure code or it throws an exception (in the latter case the "exception specification" on the function prototype will tell you that).


Sef. I don't know why you keep saying that. You obviously don't understand! Clearly you are not talking in plain English.

The exception specification only says that when you declare a function, you may have a "throw" clause. It is optional, though. You may or may not specify a "throw" clause, and it compiles either way. Also even if you specify a "throw" clause, and it is noticed by the caller of the function, you may still get OTHER types of exception that was not listed in the "throw clause", including those thrown from deep in the calling stack.

The "throw" clause of function declaration is just an un-enforceable empty promise made on the volunteer basis. You can't rely on or trust it at all.

Now step back one step, let's assume every programmer would provide a "throw" clause to their function declaration, and you can trust that no exception will be thrown except for those specified in the "throw" clause, does that guarantee that every exception thrown will be caught, at the right place where it should be caught?

NO!

The problem is in the C++ standard, caller of a function is NOT required to catch an exception thrown from a function it calls? Is that not clear? It's OPTIONAL!!! You may catch it. You may catch an exception and re-throw. Or you may just let it go and let the upper level code to catch it! It's all optional!!! When something is optional you can choose either catch it and not catch it.

The natural tendency of human laziness generally leads such a result that low level code programmer would not catch an exception, thought it would be catched by higher level code. And higher level code wouldn't catch it, thought it must have already been caught by the lower level code already. At the end of day, no one catches it.

That's what I have been saying: No body knows who will catch an exception! You can cry out loud "I am throwing an exception, some one had got to catch it." But the caller of the function is NOT required to catch it. And every one thinks some one else will catch that exception. That's the problem.

It is exactly because the caller of a function is NOT required to catch an exception and it can optionally let it propagate to higher level, that some programmer feel exceptions make it easier to handle error conditions. But the same reason is also the reason why people don't catch exceptions because they always thought it is some one else's responsibility to catch the four lettered exception.

That's why exception is evil. It let's you get away with the easy feeling of not having to handle the error yourself. But you can't get away from proper error handling at each and every level of function call. You get away and you pay a price for it.

AnthonyMai
January 28th, 2003, 01:15 PM
Just out of curiosity here.... What type of companies do you guys work for? What type of projects do you guys work on? Do you write complete solutions for your company/customers or do you write libraries for others to use? I think this will enlighten me (somewhat anyway) as to why people have the opinions they do.

I'm particularly interested in what Galathaea, Anthony Mai, Paul McKenzie, and Sef do. (Of coarse I'd be interested in what the rest of you do too...)


I work for something that must work efficiently and reliably all the time and that it is completely impossible to treat the customer's machine as your QA test machine.

<< DELETED BY THE ADMIN - Brad >>

KevinHall
January 28th, 2003, 02:04 PM
:mad: Anthony, what you just wrote is flat out disrespectful! :mad: It's one thing to voice your opinion or even argue about programming concepts (even if your views do go against a vast majority of others), but to start jumping to conclusions and making demeaning comments about other people's jobs and character is innappropriate and should be unacceptable!

I have to say you get on people's nerves very easily in these forums, and I am trying to understand where you come from [i.e. if you work in a fast-paced environment, where you have to take ultimate responsibility for safety yourself, despite any mistakes other people might make downline, then I can understand why you wouldn't want to use exceptions (and can understand some of the stances you take on other topics) -- though personally I have to disagree with a lot of them!] But it has become obvious that you lack any semblance of self control and that attempting to discuss anything with you is almost entirely fruitless! I will voice right now what I bet many others are feeling: Please do not post any longer on Code Guru -- a great forum like this does not need to be polluted by characters such as yours!

Paul McKenzie
January 28th, 2003, 02:07 PM
Originally posted by AnthonyMai
<< REMOVED BY ADMIN>>What a ****nerve you have. Answering for others that you don't know and disparaging what you think they do for a living. If this latest response from you doesn't get you banned from CodeGuru, no response will. The moderator will get a call.

You have no idea where I and others work, or what we do. I have worked from the science field in computing, to being a computer science professor, to producing third party image processing libraries, and more things that I have gotten involved with. I'm no salesman and I've been in computing for 23 years.

Also, you have a lot of nerve of assuming what others do here and to disparage others here. You are as unprofessional in your responses related to programming as you are to your fellow programmer. And yes, I have been responsible for hiring programmers -- given your lack of control, you would not have been hired by me, regardless of how much you think you know.

Regards,

Paul McKenzie

Surgeonde
January 28th, 2003, 02:48 PM
The subject differs from the mesage body.
To Clarify:
You have a C++ program, which calls C functions in compiled library.
No problem
you encapsulate
the include file of the library or the prototypes
in
extern "C" {

your includes or protypes
and then

}

If you have compiled C++ library
and a C program which calls functions in the library, then it is a little bit more complicated, but possible.

Brad Jones
January 28th, 2003, 03:15 PM
And with Surgeonde's posting, I'm closing this thread. If the technical topic needs further discussion, a new thread can be created.


Just a reminder to everyone, this site has an acceptable use policy. There is a link at the bottom of every page (AUP). Negative comments towards others (regardless of what they may have said or done) are not acceptable. By using this site, you agree to this. Please keep the public forums focused on the technical topics and issues without attacking or making negative comments towards other posters. If you feel something is questionable, then state it in a private message.

Thanks,
Brad!