Hey guys,

How do you handle exceptions in your programs? For instance, I have this function:

bool load_file(const char *filepath, std::string &dest)
throw (std::bad_alloc, std::runtime_error) {
    using namespace std;

    ifstream file;
    file.open(filepath, ios::binary);
    if (!file.good()) {
        throw runtime_error("Couldn't open the file");
    }

    //get filesize in bytes from ifstream
    //seek end, get pointer, rewind
    file.seekg(0, ios_base::end);
    size_t file_size = file.tellg();
    file.seekg(0, ios_base::beg);
    if (!file.good()) {
        throw runtime_error("Fatal error while getting filesize.");
    }

    //read file in string from ifstream
    //allocate array, read file in array, set the term. null byte, set string to array

    char *file_content;
    try {
        file_content = new char [file_size+1];
    } catch (bad_alloc &memException) {
        cerr << "Probably went out of memory while allocating " << file_size+1 << " bytes!" << endl;
        file.close();
        throw;
    }

    file.read(file_content, file_size);
    file_content[file_size] = '\0';
    dest = file_content;

    //clean up
    //close file, free array
    file.close();
    delete[] file_content;

    return true;
}

How would I handle the throw at line 7? Only with a try-catch block, or is it also possible to call the exception.what() in the terminate function?

Here's the rest of the program, I'd like to make my terminate function show what went wrong, to really have 1 central place for all the fatal errors.

#include <iostream>
#include <fstream>
#include <string>
#include <new>

#include <stdexcept>

/* load_file(filepath, destination)

   -Returns whether it succeed or not. True meaning succeeded.
   -Takes a path and writes to a std::string, completely memory safe.
*/

bool load_file(const char *filepath, std::string &dest)
throw (std::bad_alloc, std::runtime_error) {
--------------------cut here--------------------

    return true;
}

void custom_terminate() {
    std::cerr << "--Aye, unrecoverable exception thrown!\n"
    << "Try doing what the messages say (if anything) and run the program again or ask someone with a bit more expertise to help you out." << std::endl;
    std::abort();
}


int main() {
    using namespace std;

    set_terminate(custom_terminate);

    string file_content;
    load_file("test.sss", file_content);
    cout << file_content;

    return 0;
}

Recommended Answers

All 7 Replies

Of course, you need try-catch construct to intercept exceptions. Nobody can call what() member function without alive (raised) exception object: what() of ... what?

What's a problem?

int main()
{
  int rc = 0;
  // prologue
  try {
    // processing
  }
  catch (runtime_error& ups) {
    cerr << ups.what() << ...
    rc = 1;
  }
  ... other selected exception handlers
  catch (...) { // (total crash ;)
    cerr << "*** unknown exception..." ...
    rc = 2;
  }
  // epilogue
  return rc;
}

Hmz, okay. There's no way of catching the exception "going on" ? I can only check whether there's one (from anywhere in the code?), but not which one?

I believe you do in fact catch the exception as it is "going on". And since you can catch different exception types, you can tell which is which.

Here's a simplified version of loadFile. More ... stringy. Less ... errory.

#include <iostream>
#include <fstream>
#include <string>
#include <stdexcept>

std::string loadFile ( const char* path )
    throw (std::runtime_error) {
    std::string fileContent;
    std::ifstream fin ( path );
    if ( !fin ) throw std::runtime_error ( "Couldn't open file" );
    std::string line;
    while ( getline ( fin, line )) {
        fileContent += line;
        fileContent += '\n';
    }
    return fileContent;
}

int main ( int argc, char** argv ) {
    std::string file = loadFile ( "myfile.txt" );
    std::cout << file;
}

Think again about exception handling pragmatics. You raise exception deep inside a function call stack when a (relatively) low level function does not know what to do in this case or it can't inform user because it has no access to user interface (console?.. windows?.. or it's a service w/o UI? ). Another example: your function detected i/o error and can't continue but this program user has very confused notions about files, databases and other computer rattles. Let my boss(es) decides what to do and how to inform my user in this case: that's exception raising logics.

On the one hand you can react to possible failures on the right level, on the other hand you can improve your code: no need in awkward "if return code is OK" cascades now. To raise an exception is a natural method to react on failures in class constructors (they can't inform about failures via return codes).

That's why I can't understand your question: There's no way of catching the exception "going on" ? I can only check whether there's one (from anywhere in the code?), but not which one? You can catch different classes of exceptions by different catch clauses:

try {
  ...simple and clear mainstream code
}
catch (can_t_open& ex) {
  ...
}
catch (can_t_close& ex) {
  ...
}
catch (we_re_done_for& ex) {
  ...
}
catch (...) // other troubles
  ...
}

Some remarks on your example code. The loadFile function returns boolean value. Evidently it's a classical return code: true if all done or false on failure. However the only possible return code value is true (if the function can't open file it raises an exception). That's a good example of inconsistent design. Yet another defect: in critical situation (no more memory) your function prints the message to consiole then reraises an exception. Ok, now you have a good chance to be aborted (because probably stream i/o routines want memory too) then you (probably) will get yet another "no memory" message(s) from this exception handler(s) - and you can't reuse this wonderful fucntion in GUI environment (no cerr in GUI programs)...

Apropos: the simplest way to check stream state is:

if (!f) { // eof, bad or failed states
    ...

The true or false return was from the earlier version, was to be removed, you're right.

The second defect, I hadn't noticed. But it is a defect for sure? New doesn't allocate any memory since it can allocate the whole block right? So, new doesn't allocate blocks of half the size you wanted, just because he couldn't get it all. New allocates either zero bytes or all the requested bytes? In that case, there will be no problem I think: Program can't allocate all memory, gets none, lots of memory free, plenty for the error message.

On the other part (using cerr), I'm not sure what to do about it. Maybe I'll reroute output from cerr to another ofstream in case I want to create a program with a GUI.

Apropos: That saves typing 7 chars. I think I can handle those. ;)

About the second point. I think that error message printing on too low level is a very harmful practice. In that case we have a chance to get a bucket of messages on a single failure. Besides that low level routines can't print sensible messages because they have no wide context info. For example, the only sqrt calculation routine message is "Alas, my argument is lesser than zero" - well, it can't be helped. Now you can't use this damned routine in GUI codes - std::cerr object does not exist there...

I'm not sure that exception on open file operation failed is a good idea (of course, it depends on developed system architecture). As usually we don't open files in every line of code. It's not so hard to check return code from loadFile routine (file is loaded or not loaded). Exceptions are suitable for extraordinary, as usually fatal (global) events. Yet another example of local failures where exceptions are suitable: get next token calls in syntax parsers (or get next CSV field in data importers). We can avoid annoying return code checks if getnexttoken will raise an exception if no token or bad token detected. We'll catch this exception locally, make recovery, print sensible message etc.

commented: Clear explanation. +1

Thanks for that explanation. :) It makes sense.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.