Try to catch using RAII?

I have a class that has some methods like the following (and more):

template<class T> Logpp& operator<<(T const& obj) { *p_Stream << obj ; return *this ; } Logpp& operator<<(char const* zString) { *p_Stream << zString ; return *this ; } Logpp& operator<<(std::ostream& (*manip)(std::ostream&)) { *p_Stream << manip; return *this ; } 

I want to enclose the body of functions in a catch try block of the form:

  Logpp& operator<<(std::ostream& (*manip)(std::ostream&)) { try { *p_Stream << manip; return *this; } catch(ios_base::failure& e) { //MyException has a stringstream inside and can use operator<< throw MyException("IO failure writing to log file : ") << e.what() << endl; } } 

Q1: Is it appropriate to use such exceptions? (In each function). I am not familiar with exceptions, so I'm not sure.

Q2: If the answer to Q1 is yes, can I do something like this to remove the redundancy?

  Logpp& operator<<(std::ostream& (*manip)(std::ostream&)) { Catch<ios_base::failure> tc(); try { *p_Stream << manip; return *this; } //destructor of tc will be written to catch the template exception type and rethrow as a MyException. } 
+4
source share
4 answers

Q1: Is it appropriate to use such exceptions? (In each function). I am not familiar with exceptions, so I'm not sure.

There is no particular problem, but there is no particular reason if you do not plan to enrich the information on exceptions, distinguish some ios_base :: fail functions from others, etc. You only want to make each function larger / more complex if it makes something even smaller / simpler.

Q2: If the answer to Q1 is yes, can I do something like this to remove the redundancy?

You can use a macro to create try / catch blocks for you. If you do what you propose, then the destructor will be called during the exception handling: if you try to reset again, terminate() will be called. For more details, see the C ++ Lite FAQ: http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.9

+6
source

Answer to Q1: meh ...

Answer to Q2: nope, the destructor body will always be launched and will not receive any exception data. Therefore, you cannot replace the catch clause.

Even if you could, it does not fall under the term RAII. This is similar to RAII in that the use of automatic memory rules is used to invoke certain things, but more on that. Where, for example, (R) is the source, which is (A), ...

+3
source

Ad Q1:

I would recommend a little against this. Exceptions must be completed when the caller, who ultimately handles the exception, does not need to know about the internal details, and the original exception does not make sense. But for operator<< throwing std::ios_base::failure makes sense, so I won’t wrap it here.

Ad Q2:

No, but you can do something like:

 Logpp& do_output(std::ostream& (*manip)(std::ostream&)) { *p_Stream << manip; return *this; } Logpp& operator<<(std::ostream& (*manip)(std::ostream&)) { return wrap_exception(&Logpp::do_output, this, manip); } 

(maybe a little easier to use bind from TR1 / Boost as

  return wrap_exception(bind(&Logpp::do_output, this, manip)); 
+3
source

Completing exceptions is what you need to do only if you are sure what you need - it is usually not useful.

You cannot catch an exception from the destructor, but you can do the following:

 void handleCurrentException() { try { throw; } // rethrow currently active exception catch (ios_base::failure& e) { // exception handling/rethrowing code } } Logpp& operator<<(std::ostream& (*manip)(std::ostream&)) { try { *p_Stream << manip; return *this; } catch(...) { handleCurrentException(); } } 

Here, the enumeration code is short, so it might not be worth it. If the exception handling code is long, it can be useful.

0
source

Source: https://habr.com/ru/post/1339142/


All Articles