Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
roth_stephan_clean_c20_sustainable_software_development_patt.pdf
Скачиваний:
29
Добавлен:
27.03.2023
Размер:
7.26 Mб
Скачать

Chapter 5 Advanced Concepts of Modern C++

Here is a small example of the DivisionByZeroException class:

int divide(const int dividend, const int divisor) { if (divisor == 0) {

throw DivisionByZeroException(dividend);

}

return dividend / divisor;

}

int main() { try {

divide(10, 0);

}catch (const DivisionByZeroException& ex) { std::cerr << ex.what() << std::endl; return 1;

}

return 0;

}

Throw by Value, Catch by const Reference

Sometimes I’ve seen exception objects allocated on the heap with the help of new and thrown as a pointer, like in this example:

try

{

CFile f(_T("M_Cause_File.dat"), CFile::modeWrite);

//If "M_Cause_File.dat" does not exist, the constructor of CFile throws an exception

//this way: throw new CFileException()

}

catch(CFileException* e)

{

if( e->m_cause == CFileException::fileNotFound) TRACE(_T("ERROR: File not found\n"));

e->Delete();

}

207

Chapter 5 Advanced Concepts of Modern C++

Perhaps you have recognized this C++ coding style: throwing and catching exceptions in this manner can be found in the good old MFC (Microsoft Foundation Classes) library galore. And it is important that you don’t forget to call the Delete() member function at the end of the catch clause; otherwise you can say “Hello!” to memory leaks.

Well, throwing exceptions with new and catching them as a pointer is possible in C++, but it is bad design. Don’t do it! If you forget to delete the exception object, it will result in a memory leak. Throw the exception object by value, and catch them by const reference, as can be seen in all the previous examples.

Pay Attention to the Correct Order of Catch Clauses

If you provide more than one catch clause after a try block, for example to distinguish between different types of exceptions, it is important that you do so in the correct order. Catch clauses are evaluated in the order they appear. This means that the catch clauses for the more specific exception types must come first. In the example in Listing 5-30, exception classes DivisionByZeroException and CommunicationInterruptedException are both derived from std::exception.

Listing 5-30.  The More Specific Exceptions Must Be Handled First

try { doSomethingThatCanThrowSeveralExceptions();

}catch (const DivisionByZeroException& ex) {

//...

}catch (const CommunicationInterruptedException& ex) {

//...

}catch (const std::exception& ex) {

//Handle all other exceptions here that are derived from std::exception

}catch (...) {

//The rest...

}

The reason is obvious, I think: let’s assume that the catch clause for the general std::exception would be the first one, what would happen? The more specific ones below would never get a chance because they are “hidden” by the more general one. Therefore, developers must be sure to put them in the correct order.

208