-1

I have written a class to control mandatory input on an istream, based on the original idea posted there: https://stackoverflow.com/a/14331519/3723423 . It verifies and skips mandatory formatting chars, a little bit like with scanf(), but with a stream semantic:

int country; string phone;
cin >> mandatory_input(" ( + ") >> country >> mandatory_input(" ) ") >> phone;  

The class is consistent with standard istream operations, setting failbit in case of non compliant input, and throwing exceptions if and only if exceptions(istream::failbit); was set.

I have questions for improving error processing when class is used with exceptions:

  • Alternative 1: put error information in a static member. That's my current solution.

  • Alternative 2: throw my own exception class derived from istream::failure, with all information about error conditions. That would be the most elegant solution. Is there a way to throw my own exception AND set the failbit ? If I set failbit, an exception is thrown before I can throw my own. But if I don't set it, I'm not consistent with standard operations. (Edit: If I temporarily deactivate exceptions before I set faibit, the std exception is throws as soon as I reactiveate exceptions, again not giving me a chance to throw my own.)

  • Alternative 3: is it possible to set the error code that is thrown by standard exception when failbit is set ? Unfortunately, after having read about std::io_errc and std::make_error_code(), it's still not clear how I could make the failbit exception using my own error code.

Here the piece of code where error is set:

...
else if ((c = is.get()) != *p) {   // input char not matching expected char
    is.putback(c);
    mandatory_input::read_error = c;  
    mandatory_input::expected = *p; 
    // <==== Here I would like to trigger my own exception or predefine error code thrown by standard exception
    is.setstate(std::ios::failbit); // stop extracting
}
Community
  • 1
  • 1
Christophe
  • 68,716
  • 7
  • 72
  • 138
  • May be what's written up [here](http://stackoverflow.com/a/24520662/1413395) or [here](http://stackoverflow.com/questions/23047052/why-does-reading-a-struct-record-fields-from-stdistream-fail-and-how-can-i-fi) helps to solve your problems. Don't use exceptions to provide program logic BTW. – πάντα ῥεῖ Jul 13 '14 at 19:18
  • @πάνταῥεῖ thanks for links. However they appear not address my question: I have no issue about skipping chars and controlling that they meet expectations. My question is solely about tailoring the standard error processing. I'll leave the choice of using exceptions or not to the customers of my class. As you seem to be a stream expert, would you have any other hint ? – Christophe Jul 13 '14 at 19:37
  • _'As you seem to be a stream expert, ...'_ Woah, no! Way off! [@Dietmar-Kühl](http://stackoverflow.com/users/1120273/dietmar-k%C3%BChl) could be considered such expert maybe. Certainly not me :-P ... As for my 2nd link, I meant this answer in particular: http://stackoverflow.com/a/23070803/1413395 Should be possible to have a validating extractor, that optionally throws on failed extraction. – πάντα ῥεῖ Jul 13 '14 at 19:41
  • You're right: my class follows exactly the same principle than what is proposed in this answer. Its just specialised on skipping a sequence of specified chars instead of rreading a field. However, the answer does not address error processing either. – Christophe Jul 13 '14 at 19:58
  • Could you elaborate on what needs to be "improved" with the error processing of `mandatory_input`? – David G Jul 13 '14 at 20:24
  • @0x499602D2 in fact with improved, I mean alternative 2 or 3: "provide more precise information on the error but yet using the mechanisms that exist in standard". The questions to answer are in **bold**. – Christophe Jul 13 '14 at 20:36
  • What's the use for your custom exception? Is it for using `read_error` and `expected`? – David G Jul 13 '14 at 21:23
  • The idea is to subclass istream::failure(). The catcher may then easily choose whether he wants to specifically process mismatch errors or jus the general failure. This would also give me the opportunity to send a specific error message, so that the e.what() in exception processing could return more accurate messages, whatever the catcher does. – Christophe Jul 13 '14 at 21:45

1 Answers1

1

I was so concentrated on searching std functions to solve that, that I didn't think of the most obvious solution: hijacking the std exception thrown. In case it could help s.o. else:

I first defined a dedicated nested failure class:

class mandatory_input { 
public:
...
    class failure : public std::istream::failure {
    public: 
        failure(std::error_code e);
    };
};

Then I have added the following bloc in the original error processing code (see question):

    // start of enhanced exception handling     
    if (is.exceptions() & std::istream::failbit) {  // if exception will be thrown
        try { 
            is.setstate(std::ios::failbit);
        } catch (std::istream::failure &e) {  // the failbit will trigger this
            throw mandatory_input::failure(e.code());  // and i throw my own
        } catch (std::exception &e) {   // just in case other low-level errors would be thrown 
            throw e;
        }
    } else  //======= end of enhanced exceptions handling 

Now with this solution, the clients of my helper class who want to use .exceptions() can process errors either undifferentiated:

try { cin >> mandatory_input(" ( + ") >> country >> .... ;  
} catch (istream::failure e) {
cerr << "Input error: "<< e.code()<< " " << e.what(); 
}

or fine tune error processing:

try {  ....   
} catch (mandatory_input::failure e) {
cerr << "Input format mismatch: " << mandatory_input::getexpected()
      << " was expected, but " << mandatory_input::getread_error() << " was read !\n";
} catch (istream::failure e) {
cerr << "Input error: "<< e.code()<< " " << e.what(); 
}
Christophe
  • 68,716
  • 7
  • 72
  • 138