Function Exception Specification and Standard Exceptions - foo () throw (Exception)

In C ++, you can declare a function with an exception specification as follows:

int foo() const throw(Exception); 

I found these two links:

But some things ultimately go unanswered ...

Question 1: why add an exception specification? Will this lead to increased productivity? What will be different for the compiler? Because it is like information for a programmer.

Question 2: what will happen (what should happen) if I drop something that is not specified in the specification? For instance:

 int foo() throw(int) { throw char; // Totally unrelated classes, not types in real } 

Question 3: function / method should not throw anything. I found at least two (three, alternative syntax for different compilers) ways to specify an exception exception:

  • int foo() throw();
  • int foo() __attribute(nothrow)__ for gcc
  • int foo() nothrow for visual c ++

Which one is "correct"? Is there any difference? Which one should I use?

Question 4: "standard exceptions", bad_alloc , bad_cast , bad_exception , bad_typeid and ios_base::failure .

Ok bad_alloc explains itself, and I know how (and more importantly, when) to use it (add exceptions to the specification), but what about others? None of them really ring the bell ... What "code fragments" are they associated with? How bad_alloc is related to new char[500000] .

Question 5: If I have a hierarchy of exception classes, for example:

  class ExceptionFileType { virtual const char * getError() const = 0; }; class ExceptionFileTypeMissing : public ExceptionFileType { virtual const char *getError() cosnt { return "Missing file"; } } 

Should I use:

  int foo() throw(ExceptionFileType); 

Or:

  int foo() throw(ExceptionFileTypeMissing,ExceptionFileTypeNotWritable,ExceptionFileTypeNotReadable,...) 

Note: answers with links will be great. I am looking for good practice advice.

+4
source share
4 answers

A simple โ€œgood practiceโ€ tip: do not use exception specifications.

In fact, the only exception is the ability to create an empty exception specification: throw() . It is useful enough that in C ++ 11 he was provided with his own keyword ( noexcept ). In general, it was decided that any nonempty specification of exceptions, however, is a lousy idea.

Exclusion specifications (except for noexcept ) are officially outdated - and unlike many legacy functions, deleting this can affect the insufficient source code, which, I think, has a good chance that it will be deleted (of course, there is no guarantee, but a pretty good opportunity )

As for what happens when / if you throw an exception of a type not allowed by the exception specification: std::unexpected() is called. By default, this calls terminate() . You can use std::set_unexpected to set your own handler, but all you can do is add a few logs before you terminate() . Your unexpected handler cannot return.

+6
source

Question 1

Do not worry. They were a bad idea and were deprecated in the latest version of the language. They do not bring any benefit to the compiler, since they are checked at runtime; in any case, they can damage performance in some cases.

Question 2

A function called std::unexpected called. By default, this calls std::terminate ; by default, this terminates the program. Both of these behaviors can be changed using std::set_unexpected and std::set_terminate to set your own handler if you really want to.

Question 3

throw() was the standard way to do this; others are not portable compiler extensions. In C ++ 11, you can use noexcept , which gives a compile-time check that nothing can do, and not a runtime check that doesn't throw anything.

Question 4

  • bad_cast is called when the <<27> link is down.
  • bad_exception is bad_exception in some strange circumstances when the exception specification is violated.
  • bad_typeid is called if evaluating the typeid argument involves dereferencing a null pointer
  • ios_base::failure is output by the I / O library ( <iostream> etc.) when some operations fail

Question 5

If you want to allow all heroism, then just specify the base class. But you should not use exception qualifiers.

+3
source

First, let's make it very clear what the exception specification makes: it is more or less like assert , which cannot be disabled, asserting that you will not exit the function with an exception other than those missing. Thus, this utility is much more limited than it would seem in the first place; for the most part (in which case I cannot imagine an exception), the only really useful guarantee is throw() , which ensures that the exception will not be thrown; if you want to write excluding safe code, you will need this guarantee for several low-level functions.

In practice, although throw() may allow some additional optimization compiler, a common implementation tends to result in less efficient code when the exception specification is used. In C ++ 11, throw() was replaced with noexcept , presumably with the hope that compiler developers would do something clever with it.

EDIT:

Since everyone (including me) seems to have missed your question 4:

bad_alloc will be called by the operator new function if it cannot allocate memory.

bad_cast will be discarded by a dynamic_cast link, in the event that a failure occurs. (A dynamic_cast pointer returns a null pointer in such cases.)

bad_exception will be thrown if the exception specification is violated, if the exception specification allows bad_exception . (In other words, forget about it.)

bad_typeid will be reset if you try to use typeid with a null pointer.

ios_base::failure will be reset if you request a thread for an error case.

Practically speaking: you will catch bad_alloc if you want to recover and continue working due to lack of memory. This does not mean very often. (This is very, very difficult to recover because of the memory situation.) For bad_cast , it is probably preferable to use pointers and check for null if you are not sure. And there is no excuse to see bad_typeid forever. In most cases, you probably want to check for I / O errors explicitly, rather than setting up a thread to throw exceptions; as well as an exception when installing ios_base::badbit may be an exception (since it is a really exceptional case of a hard error).

+2
source

Questions 1 and 2 are addressed to some extent in this issue .

Questions 3 and 5 are covered by the recommendation in the accepted answer to this question that you do not use exception specifications at all.

Question 4 seems to be adequately addressed by entering these exception names into the search engine of your choice or by advising the index of a good C ++ book. Do you have a specific request for them?

+1
source

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


All Articles