123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- <chapter xml:id="error.h">
- <title><tt>__vic/error.h</tt></title>
- <p>Error handling tools.</p>
- <chapter xml:id="exception">
- <title><tt>exception</tt></title>
- <code-block lang="C++">
- class exception : public std::exception
- {
- public:
- exception();
- explicit exception(const char *message);
- const char *what() const noexcept;
- protected:
- void set_message(const char *message);
- };
- </code-block>
- <p>Small extension of <tt>std::exception</tt> - the object carries message
- specified in the constructor, <tt>what()</tt> returns this message. Can be used
- either as a base or a concrete exception class. Does not use/depend on
- <tt>std::string</tt> as opposed to <tt>std::logic_error</tt> and
- <tt>std::runtime_error</tt>. You also don't have to decide which one of them
- you should use in the particular case.</p>
- <section><title>Class members</title>
- <synopsis>
- <prototype>exception()</prototype>
- <p>Creates the object with an empty message.</p>
- </synopsis>
- <synopsis>
- <prototype>explicit exception(const char *message)</prototype>
- <p>Creates the object with the specified message.</p>
- </synopsis>
- <synopsis>
- <prototype>const char *what() const noexcept</prototype>
- <p>Returns the message specified before.</p>
- </synopsis>
- <synopsis>
- <prototype>void set_message(const char *message)</prototype>
- <p>Sets a new message.</p>
- </synopsis>
- </section>
- <section><title>Example</title>
- <code-block lang="C++">
- struct custom_exception : public __vic::exception
- {
- explicit custom_exception(const char *msg) : __vic::exception(msg) {}
- };
- throw custom_exception("Error condition description");
- </code-block>
- </section>
- </chapter>
- <chapter xml:id="libc_error">
- <title><tt>libc_error</tt></title>
- <code-block lang="C++">
- class libc_error : public std::exception
- {
- public:
- explicit libc_error(int err_no = errno);
- explicit libc_error(const char *prompt, int err_no = errno);
- const char *what() const noexcept;
- int code() const;
- int get_errno() const;
- };
- </code-block>
- <p>This class is an easy and straightforward replacement of the standard error
- handling machinery used in the C-world - <tt>errno</tt>, with exceptions. The
- class is also suitable for usage in the multithread environment instead of
- not always reentrant call <tt>std::strerror()</tt>.</p>
- <p>Below you can see typical C code:</p>
- <code-block lang="C">
- // C:
- int fd;
- if((fd = open("qqqq", O_RDONLY)) == -1)
- {
- perror("open");
- if(errno == ENOENT) exit(1);
- }
- </code-block>
- <p>If the file is not found, the message like this</p>
- <tty>
- open: No such file or directory
- </tty>
- <p>is printed to <tt>stderr</tt> and the program exits with the status
- <tt>1</tt>.</p>
- <p>What issues are inherent in this code? Firstly, not every program has
- <tt>stderr</tt>, so a library function is not allowed to print error messages
- there. Secondly, the value of the global variable <tt>errno</tt> can be
- rewritten by any subsequent call unless the value is saved explicitly right
- after the call. Thirdly, the decision about termination of the process can only
- be made by the application. An ordinary library function is not allowed to do
- this. Fourthly, in general case C++ program cannot call <tt>std::exit()</tt>,
- because destructors of the live objects allocated on the stack won't be
- called, and program's logic can be corrupted.</p>
- <p>The example adapted for C++ using our class:</p>
- <code-block lang="C++"><![CDATA[
- // C++:
- try
- {
- int fd = open("qqqq", O_RDONLY);
- if(fd == -1) throw __vic::libc_error("open");
- // or just
- // if(fd == -1) throw __vic::libc_error();
- }
- catch(const __vic::libc_error &ex)
- {
- std::cerr << ex.what() << '\n';
- if(ex.code() == ENOENT) return 1;
- }
- ]]></code-block>
- <p>As it can be seen, the function handles erroneous situation correctly and
- reports it to the caller. Afterwards the caller can handle the error
- appropriately. In the elementary case it acts as the former C-program: prints
- the message to the standard error output stream and terminates. Moreover,
- error code is now saved in the exception and cannot be rewritten by accident.
- </p>
- <note>Usually exceptions of this class shouldn't be thrown explicitly! Use
- <xref to="throw_errno"/> instead.</note>
- <section><title>Class members</title>
- <synopsis>
- <prototype>explicit libc_error(int err_no = errno)</prototype>
- <p><tt>err_no</tt> - error code.</p>
- <postcondition><tt>code() == err_no</tt></postcondition>
- </synopsis>
- <synopsis>
- <prototype>explicit libc_error(const char *prompt, int err_no = errno)</prototype>
- <p><tt>prompt</tt> - a title of the error message. The parameter has the same
- meaning as the parameter of <tt>std::perror()</tt>.</p>
- </synopsis>
- <synopsis>
- <prototype>const char *what() const noexcept</prototype>
- <p>Returns error description in the <tt>std::perror()</tt> format.</p>
- </synopsis>
- <synopsis>
- <prototype>int code() const</prototype>
- <prototype>int get_errno() const</prototype>
- <p>Returns stored error code.</p>
- </synopsis>
- </section>
- </chapter>
- </chapter>
|