I have a question about exceptions.

This is a discussion on I have a question about exceptions. within the C++ Programming forums, part of the General Programming Boards category; > The file not found example is used assuming the reader understands that the situation is something like a situation ...

  1. #16
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Portugal
    Posts
    7,581
    > The file not found example is used assuming the reader understands that the situation is something like a situation where code attempts to open a file with an unchecked, user specified filename for a non-essential file.

    Bah! My bad. Thanks for clarifying that Daved.
    The programmer’s wife tells him: “Run to the store and pick up a loaf of bread. If they have eggs, get a dozen.”
    The programmer comes home with 12 loaves of bread.


    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  2. #17
    Registered User
    Join Date
    Jun 2005
    Posts
    6,662
    Quote Originally Posted by Mario F.
    Gosh I'm so confused...

    EDIT: But isn't true that the reason to decide or not to throw should be based solely on who/what is going to handle the error?

    - The code that causes the error can handle it. Strong case against exceptions.
    - The code can't handle it. Strong case for exceptions.

    I'm sorry to keep hitting on the same thing. I'm daft. It's just that my perfect world is crashing with every post you gurus make.
    The real world seems to stop being perfect every time gurus attempt to walk on water.

    Another criterion for deciding if it is appropriate to throw an exception is criticality of the error (i.e. the consequences if no recovery actions are taken). If nothing will break, there is no need to force the issue should no recovery action being taken. Throwing an exception is a way to force the issue (if the exception is not handled, the program will terminate and, normally, any code that catches an exception will take some recovery actions). Failure to open a non-critical file is one example of a non-critical error. Reaching end of file, when end-of-file is a condition for terminating a loop, is another non-critical error.

  3. #18
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Portugal
    Posts
    7,581
    And yet... the seriousness of the error should be a decision of the caller.
    The programmer’s wife tells him: “Run to the store and pick up a loaf of bread. If they have eggs, get a dozen.”
    The programmer comes home with 12 loaves of bread.


    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  4. #19
    Registered User
    Join Date
    Jun 2005
    Posts
    6,662
    Quote Originally Posted by Mario F.
    And yet... the seriousness of the error should be a decision of the caller.
    Not always. It is often possible, at the point where an error is detected, to know how critical it is even if there isn't knowledge at that point about how to recover from it. For example, failure to dynamically allocate memory is often considered a critical error (when it occurs once, it is a fair bet that hard resource limitations are being reached, and other errors will occur unless some recovery occurs). It is also something that, technically, is recoverable, but the recovery schemes are pretty much outside the control of most programs (eg getting the user to shut down other applications, plugging in additional memory). This is one of the reasons operator new throws exceptions (by default) when it fails: the error is critical (meaning it can only be ignored at peril), but technically recoverable (which means it is not necessary to terminate the program immediately) and usually not able to be recovered from when the error is detected.

  5. #20
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Portugal
    Posts
    7,581
    Lets consider the file open issue.

    - file name is given by the user (I'm making this ever easy to choose against a throw)
    - failure to open the file is non critical. Program can happily move on.

    but...

    - code to actually open a file is in a different module.

    This is my point, grumpy. And where I defend an exception should be throw by the code that opens the file. Certainly, if you don't ever plan to reuse that code why bother with an exception. But can you safely make that decision? Or, is it a good decision design-wise?

    The user of the module can easily bypass the exception if he wants to, by checking himself if the file exists... or can use the facilities provide by the module and do a try-catch. Their choice. However the module offers him that flexibility.

    Arguably the function call inside the module may return false. It's a pretty easy thing to deal with. But what if they reused the module to handle critical files? Suddenly the user is left with the responsability of cleaning up and aborting, when a rethrow would have been a much cleaner solution.
    The programmer’s wife tells him: “Run to the store and pick up a loaf of bread. If they have eggs, get a dozen.”
    The programmer comes home with 12 loaves of bread.


    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  6. #21
    Darkness Prevails Dark_Phoenix's Avatar
    Join Date
    Oct 2006
    Location
    Houston, Texas
    Posts
    174
    Quote Originally Posted by Mario F.
    Gosh I'm so confused...
    Don't feel bad, Mario. I thought I knew a few things about exception handling until I read this thread... Now I need to reevaluate that knowledge.....
    Using Code::Blocks and Windows XP

    In every hero, there COULD be a villain!

  7. #22
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Portugal
    Posts
    7,581
    Well, I just had an epiphany.

    If I'm so sure of what I just said... why then I don't see that all over the STL?

    There's only one answer to that.
    The programmer’s wife tells him: “Run to the store and pick up a loaf of bread. If they have eggs, get a dozen.”
    The programmer comes home with 12 loaves of bread.


    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  8. #23
    Registered User
    Join Date
    Jan 2005
    Posts
    7,344
    >> Another criterion for deciding if it is appropriate to throw an exception is criticality of the error.
    I'm not disagreeing, but the criticality of an error is still all part of whether an error can be handled at the point at which it happens. If nothing will break in the current code, then the error can be handled. Handling that error is part of the function or module's expected behavior and is hopefully documented.

    >> Lets consider the file open issue.
    In explaining that situation, you're looking at if from the wrong perspective. If the code to open the file is in another module, then the facts that the filename came from the user and that the program can happily move on are less relevant. From the perspective of that module the facts are:

    - Filename came from calling code elsewhere in the program.
    - Calling code may or may not be able to continue.
    - Module can definitely continue without error.

    My thought: don't throw an exception. That might be debatable, but the point is that you have to look at it from the perspective of the code you are writing. This is not a great example, and it is not what is meant by the file open example.

    Here are two file open scenarios that should be more clear:

    Scenario 1
    - Function gets filename as parameter from the caller.
    - Intent of function is to load additional non-essential initialization preferences for application.
    - Function uses fstream to attempt to open the file.
    - Loading no preferences is a valid result of calling the function.
    So, if the file fails to open, the fstream's is_open() function will return false, and the function can handle this by loading no preferences. The function can return false if it failed to load preferences if the designer chooses to do so. The situation is not exceptional.

    Scenario 2
    - Function gets filename as parameter from the caller.
    - Intent of the function is to read in necessary initialization data from a dat file.
    - Function uses fstream to open the file.
    - Application cannot run without data from the file.
    So, if the file fails to open, the fstream's is_open() function will return false, but the function cannot handle this error. It's job is to load required information from a dat file. If it cannot load that information, it cannot do its job and the app cannot continue. It should throw an exception.

    Real-world situations can get muddier, but you have to analyze each as it comes and apply the same principles. Is this situation one that can occur easily within the program. Can the error be handled. Can the function accomplish its job anyway, etc.

  9. #24
    Registered User
    Join Date
    Jun 2005
    Posts
    6,662
    Quote Originally Posted by Daved
    >> Another criterion for deciding if it is appropriate to throw an exception is criticality of the error.
    I'm not disagreeing, but the criticality of an error is still all part of whether an error can be handled at the point at which it happens. If nothing will break in the current code, then the error can be handled. Handling that error is part of the function or module's expected behavior and is hopefully documented.
    Criticality refers to consequences of the error if not corrected, not to any ability to correct the error at the point where it is detected or "where it happens". If an error is detected by some function/module examining the relationship of some objects (or data, or ...), that is not the same as saying that the either the causes or means of rectifying the error are known to that function or module.

    If there are a set of preconditions (i.e. assumptions) for the current code to work correctly, and data provided to that code violates those preconditions, then the current code can detect the error but not necessarily correct it. If the consequences of not correcting that error are likely to be severe, then it is a critical error. If the causes of the error are outside control of the current function or module (eg if the error is caused by a hardware failure), then it may be a critical error that the current function/module cannot correct.

  10. #25
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Portugal
    Posts
    7,581
    I think I can see the light!

    That last post is a keeper, Daved. Thanks a bunch. I have a lot of ruminating to do. Started this thread thinking I had it all figured out. Thanks everyone for not having given up
    The programmer’s wife tells him: “Run to the store and pick up a loaf of bread. If they have eggs, get a dozen.”
    The programmer comes home with 12 loaves of bread.


    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  11. #26
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,893
    Quote Originally Posted by Daved
    Here are two file open scenarios that should be more clear:

    Scenario 1
    - Function gets filename as parameter from the caller.
    - Intent of function is to load additional non-essential initialization preferences for application.
    - Function uses fstream to attempt to open the file.
    - Loading no preferences is a valid result of calling the function.
    So, if the file fails to open, the fstream's is_open() function will return false, and the function can handle this by loading no preferences. The function can return false if it failed to load preferences if the designer chooses to do so. The situation is not exceptional.

    Scenario 2
    - Function gets filename as parameter from the caller.
    - Intent of the function is to read in necessary initialization data from a dat file.
    - Function uses fstream to open the file.
    - Application cannot run without data from the file.
    So, if the file fails to open, the fstream's is_open() function will return false, but the function cannot handle this error. It's job is to load required information from a dat file. If it cannot load that information, it cannot do its job and the app cannot continue. It should throw an exception.
    I don't think this view is realistic. In reality, there is one piece of code called "read_config_file" that opens and parses configuration, and there are two places in the code called "read_core_config" and "read_ext_config" which call read_config_file. For the former, an error of read_config_file is fatal, for the latter, it is not.
    How should read_config_file react to an error?

    I think it should throw an exception, but read_ext_config would catch it, perhaps log it, but otherwise just carry on. Whereas read_core_config may augment or transform it, but otherwise pass it on.

    From the perspective of that module the facts are:

    - Filename came from calling code elsewhere in the program.
    - Calling code may or may not be able to continue.
    - Module can definitely continue without error.
    That module is most likely concerned with reading information from the file, so it cannot continue without error - it would be unable to perform its actions.
    I also don't think that "fall back to default values" is a good error handling strategy for explicit requests.
    In other words, if I call a module and it can't automatically find configuration and thus uses some defaults, that's fine; if I call a module telling it to use some configuration and it - because some error occurred while using that configuration - falls back to defaults, that would seriously annoy me. Talk about a source of weird bugs down the line. (Why is that config file not in /etc/tomcat-5.5 ? I specifically told it to put the file there.

    3 hours later: oh, it fell back to the default of logging to the console, which got swallowed by this startup script here.)
    Yes, that actually happened to me. Recently.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  12. #27
    Registered User
    Join Date
    Jan 2005
    Posts
    7,344
    >> I don't think this view is realistic
    Of course it is realistic. It is a specific example. Your "in reality" version is just a different example. In order to help people understand the concepts, we should stick to simple (yet plausible) examples that are fairly clear in the expected resolution.

    Obviously, as I said earlier, real-world situations can get muddier. It is important to study the muddier situations. However, let's not tear down or confuse the simpler examples in the process, or you run the risk of confusing the understanding brought by those simpler examples.

    So, in some cases maybe you want your config reader to throw an exception, and maybe in some cases you don't want your error handling to consist of using default values. That's all good, they're just different examples.

  13. #28
    The larch
    Join Date
    May 2006
    Posts
    3,573
    If I'm so sure of what I just said... why then I don't see that all over the STL?
    They aren't?

    Code:
    #include <iostream>
    #include <vector>
    #include <exception>
    
    int main()
    {
        std::vector<int> v(5, 1);
        
        try {
            for (size_t i = 0; i < 10; i++) {
                std::cout << v.at(i) << std::endl;
            }
        }
        catch (std::exception& e) {
            std::cout << e.what() << std::endl;
        }
        std::cin.get();
    }
    The containers probably also (re)throw a bad_alloc error, at least my vectors do here.

  14. #29
    Cat
    Cat is offline
    Registered User
    Join Date
    May 2003
    Posts
    1,571
    I agree, the STL does use exceptions for virtually all error handling, although the STL, being optimized for speed, does very little error checking or reporting to begin with.
    You ever try a pink golf ball, Wally? Why, the wind shear on a pink ball alone can take the head clean off a 90 pound midget at 300 yards.

Page 2 of 2 FirstFirst 12
Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Exceptions
    By sean in forum C# Programming
    Replies: 4
    Last Post: 10-01-2004, 01:48 AM
  2. Question about pointers #2
    By maxhavoc in forum C++ Programming
    Replies: 28
    Last Post: 06-21-2004, 01:52 PM
  3. Question...
    By TechWins in forum A Brief History of Cprogramming.com
    Replies: 16
    Last Post: 07-28-2003, 10:47 PM
  4. Throwing exceptions with constructors
    By nickname_changed in forum C++ Programming
    Replies: 14
    Last Post: 07-08-2003, 10:21 AM
  5. Question, question!
    By oskilian in forum A Brief History of Cprogramming.com
    Replies: 5
    Last Post: 12-24-2001, 01:47 AM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21