Russian Qt Forum
Ноябрь 15, 2024, 05:37 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 [2] 3 4 ... 7   Вниз
  Печать  
Автор Тема: [РЕШЕНО] Обработка ошибок без исключений и с помощью исключений  (Прочитано 50626 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #15 : Март 24, 2014, 19:50 »

Это что за "общее правило" такое?
Это предложение набор общих слов, ничего не выражающих. Прочтите его. Улыбающийся
Уймитесь Улыбающийся 
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #16 : Март 24, 2014, 19:53 »

Уймитесь Улыбающийся 
Это вы уймитесь нести ерунду и называть это "общими правилами". Таких правил нет и никогда не будет, потому что это бред. Улыбающийся
Кстати ваш же пример с ReadSomeData это подтверждает. Улыбающийся
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #17 : Март 24, 2014, 19:57 »

Это вы уймитесь нести ерунду и называть это "общими правилами". Таких правил нет и никогда не будет, потому что это бред. Улыбающийся
Библию почитайте, мелкий скандалист  Улыбающийся
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #18 : Март 24, 2014, 19:59 »

Библию почитайте, мелкий скандалист  Улыбающийся
Какую библию?
Я у вас уже несколько раз спрашивал, что вы под этим подразумеваете, вы всегда отмалчиваетесь. Улыбающийся
Ну ка, говорите, опять хабра начитались? Или видеокурсы "C++ за пять занятий" смотрели? Улыбающийся
« Последнее редактирование: Март 24, 2014, 20:00 от Old » Записан
Bepec
Гость
« Ответ #19 : Март 24, 2014, 21:12 »

Old, Igors дело говорит.

Исключение для чего нужно? Исключение это возможность проброса данных из глубины наверх. Каждый обработчик решает простое условие. "Я могу обработать данное исключение? Да - обрабатываю. Нет - пробрасываю дальше.".  Для обработки, для реакции на событие. Но если обработка возможна на уровне ошибки (открытие файла) тогда исключение не нужно.

Если же программа упала, значит эта ситуация не была предусмотрена разработчиками. Значит никакой информации об ошибке быть не может, ибо разработчики информации не оставили.  Так называемое необработанное исключение.

PS если вы мне подскажете документацию, в которой описывается как поймать "обращение по неинициилизированном указателю, выход за пределы массива, порчу памяти программы" и исправить, я буду благодарен. Для развития кругозора почитаю.

PPS Segmentation fault - исключение, насколько мне известно.
Цитировать
В Microsoft Windows, процесс, получающий доступ к недействительным участкам памяти, создаёт исключение STATUS_ACCESS_VIOLATION
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #20 : Март 24, 2014, 21:46 »

Old, Igors дело говорит.
Это ерунда. Обычная. Набор слов выданных с важным видом. Улыбающийся

Мы пишем функцию ReadSomeData, как нам решить использовать исключения или нет. Мы понятия не имеем, кто и когда эту функцию будет вызывать: кто-то ее позовет из main, а кто-то ее позовет из 100500 вложенной друг в друг функции.
Поэтому, это выдуманное "правило" обычный бред, выданный с важным видом что-бы произвести впечатление. Улыбающийся

Если же программа упала, значит эта ситуация не была предусмотрена разработчиками. Значит никакой информации об ошибке быть не может, ибо разработчики информации не оставили.  Так называемое необработанное исключение.
Если программа упала, значит в ней содержится ошибка, а не исключительное состояние. Не надо их путать.
Если программа завершилась из-за необработанного исключения, то разработчик не предусмотрел его обработку, но вся информацию по исключению есть и она передается вместе с исключением.

PS если вы мне подскажете документацию, в которой описывается как поймать "обращение по неинициилизированном указателю, выход за пределы массива, порчу памяти программы" и исправить, я буду благодарен. Для развития кругозора почитаю.
Еще раз, не нужно путать ошибки в программе и исключительные ситуации, это совершенно разные вещи.

PPS Segmentation fault - исключение, насколько мне известно.
Нет.
« Последнее редактирование: Март 24, 2014, 21:48 от Old » Записан
8Observer8
Гость
« Ответ #21 : Март 25, 2014, 07:10 »

PS если вы мне подскажете документацию, в которой описывается как поймать "обращение по неинициилизированном указателю, выход за пределы массива, порчу памяти программы" и исправить, я буду благодарен. Для развития кругозора почитаю.

> выход за пределы массива
Вот документация: http://www.cplusplus.com/reference/stdexcept/out_of_range/

Вот пример из документации:
Код
C++ (Qt)
// out_of_range example
#include <iostream>       // std::cerr
#include <stdexcept>      // std::out_of_range
#include <vector>         // std::vector
 
int main( void ) {
   std::vector<int> myvector( 10 );
   try {
       myvector.at( 20 ) = 100; // vector::at throws an out-of-range
   } catch ( const std::out_of_range& oor ) {
       std::cerr << "Out of Range error: " << oor.what( ) << '\n';
   }
   return 0;
}

По поводу обычных массивов и "обращения по неинициилизированном указателю" Это учли в современных языках программирования таких как C# и Java, в которых без исключений никуда. К сожалению, С++ не обязывает разработчиков применять исключения.
Записан
8Observer8
Гость
« Ответ #22 : Март 25, 2014, 09:34 »

Нам всё равно придёться мириться с исключениями, так как их выбрасывают многие функции STD. Если мы их не будем отлавливать, то программы будут падать без всяких сообщений.

Я не вижу в чём принципиальная разница между двумя подходами по обработке ошибок. Чем же здесь плохи исключения? Сравните в чём разница для пользователя, который вызывает функцию readData( iFileName, arr ). Исключения выполняют, в данном случае, туже самую работу:
Код
C++ (Qt)
   // Read data from a file
   QString iFileName = QString( "input.txt" );
   QVector<int> arr;
   try {
       readData( iFileName, arr );
   } catch ( const std::exception &e ) {
       std::cerr << e.what( ) << std::endl;
       return 1;
   }
 

Код
C++ (Qt)
   // Read data from a file
   QString iFileName = QString( "input.txt" );
   errorCode = readData( iFileName, data );
   if ( errorCode != ErrorType::errNone ) {
       return showError( iFileName, errorCode );
   }
 
« Последнее редактирование: Март 25, 2014, 09:37 от 8Observer8 » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #23 : Март 25, 2014, 10:42 »

Я не вижу в чём принципиальная разница между двумя подходами по обработке ошибок. Чем же здесь плохи исключения? Сравните в чём разница для пользователя, который вызывает функцию readData( iFileName, arr ). Исключения выполняют, в данном случае, туже самую работу:
Если сравнивать одно исключение с одной нормальной обработкой - то исключение куда дороже. Чего это Вы отделались печатью e.what(), где полный текст ошибки? Его надо добавлять и так просто как с ShowError не выйдет. Во-вторых, откуда предположение что только std::exception может быть испущено? Извольте ставить второй catch, если уж взялись.

И главное - а кто испустит exception? Оно применяется часто именно при чтении/записи.
Код
C++ (Qt)
strm >> a;
if (strm.error()) ...  // throw или возврат ошибки
...
strm >> b;
if (strm.error()) ...  
...
strm >> c;
if (strm.error()) ...  
....
Часто Вы не сможете читать "b" не проверив корректности "a" и.т.д. Общее число проверок становится невыносимым. Вот здесь разумно сделать так чтобы оператор >> испускал исключение и отловить все 1 раз наверху. Хотя и здесь некоторые предпочитают нормальную обработку.
Записан
8Observer8
Гость
« Ответ #24 : Март 25, 2014, 10:52 »

По поводу текстов ошибок, то они внутри функции readData(). Я правильно понял замечание? Что здесь непросто?

Код
C++ (Qt)
void readData( const QString &fileName, QVector<int> &dest )
throw (std::invalid_argument, std::runtime_error) {
 
   // ...
   std::string error = "Unable to open the file " + fileName.toStdString( );
   throw std::invalid_argument( error );
   // ...
 
   // ...
   std::string error = "Unable to read file " + fileName.toStdString( );
   throw std::runtime_error( error );
   // ...
}
 
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #25 : Март 25, 2014, 11:04 »

По поводу текстов ошибок, то они внутри функции readData(). Я правильно понял замечание? Что здесь непросто?
Это просто плохо, одна ф-ция и цыплят жарит, и кофе готовит и еще много чего - вот только все делает плохо  Улыбающийся
Записан
Bepec
Гость
« Ответ #26 : Март 25, 2014, 11:08 »

PPS Segmentation fault - исключение, насколько мне известно.
Нет.
Я вам специально цитату привёл Улыбающийся В Windows это является исключением Веселый

Цитировать
Скот Мейерс в своей книге "Наиболее эффективное использование С++" утверждает, что повсеместное использование исключений в программе приведёт к снижению скорости выполнения программы на 5-10%.

Исключения возникают тогда, когда некоторая часть программы не смогла сделать то, что от неё требовалось. При этом другая часть программы может попытаться сделать что-нибудь иное.
Исключения позволяют логически разделить вычислительный процесс на 2 части - обнаружение аварийной ситуации и её обработка.
Примечание: В принципе, ничто не мешает рассматривать в качестве исключений не только ошибки, но и нормальные ситуации, возникающие при обработке данных, но это не имеет преимуществ перед другими решениями и не улучшает структуру и читаемость программы.

PS собственно и получается интересная деталь - при использовании "кода с исключениями" всегда может быть ситуация, что исключений будет типов 10-15. При использовании библиотек может доходить и до 20-30. И для обработки всех событий вам придётся писать 30 блоков обработки. А у 20 из 30 исключений внутри будут разные структуры, и это становится невыносимым Веселый
Записан
8Observer8
Гость
« Ответ #27 : Март 25, 2014, 11:29 »

Это просто плохо, одна ф-ция и цыплят жарит, и кофе готовит и еще много чего - вот только все делает плохо  Улыбающийся

С данным примером согласен. А вот если писать свои классы исключений, то проблема с тем кто передаёт тексты ошибок - уходит:
Код
C++ (Qt)
void readData( const QString &fileName, QVector<int> &dest )
throw (FileOpenError, FileReadError) {
 
   // ...
   throw FileOpenError( fileName );
   // ...
 
   // ...
   throw FileReadError( fileName, lineNumber );
   // ...
 
}
 

К тому же, как видите, мы можем теперь передавать номер строки, в которой некорректные данные. А Тексты ошибок у нас теперь в классах: FileOpenError и FileReadError:

FileOpenError.h
Код
C++ (Qt)
#ifndef FILEOPENERROR_H
#define FILEOPENERROR_H
 
#include <QString>
#include "FileError.h"
 
class FileOpenError : public FileError {
public:
 
   FileOpenError( const QString &fileNameIn ) : FileError( fileNameIn ) {
       mMsg = "Unable to open " + fileNameIn.toStdString( );
   }
};
 
#endif // FILEOPENERROR_H
 

FileReadError.h
Код
C++ (Qt)
#ifndef FILEREADERROR_H
#define FILEREADERROR_H
 
#include "FileError.h"
#include <QString>
#include <QTextStream>
#include <sstream>
 
class FileReadError : public FileError {
public:
 
   FileReadError( const QString &fileNameIn, int lineNumIn ) :
   FileError( fileNameIn ), mLineNum( lineNumIn ) {
       std::ostringstream ostr;
 
       ostr << "Error reading " << fileNameIn.toStdString( ) << " at line " << lineNumIn;
       mMsg = ostr.str( );
   }
 
   int getLineNum( ) const {
       return mLineNum;
   }
 
protected:
   int mLineNum;
};
 
#endif // FILEREADERROR_H
 

FileError.h
Код
C++ (Qt)
#ifndef FILEERROR_H
#define FILEERROR_H
 
#include <QString>
#include <exception>
#include <string>
 
class FileError : public std::runtime_error {
public:
 
   FileError( const QString &fileIn ) : std::runtime_error( "" ), mFile( fileIn ) {
   }
 
   virtual const char* what( ) const noexcept {
       return mMsg.c_str( );
   }
 
   QString getFileName( ) const {
       return mFile;
   }
 
protected:
   QString mFile;
   std::string mMsg;
};
 
#endif // FILEERROR_H
 

Пользователь теперь может вызывать функцию readData( iFileName, arr ); вот так (обрабатывая все исключения):
Код
C++ (Qt)
int main( int argc, char *argv[] ) {
 
   // ...
   // Read data from a file
   QString iFileName = QString( "input.txt" );
   QVector<int> arr;
   try {
       readData( iFileName, arr );
   } catch ( const FileError &e ) {
       std::cerr << e.what( ) << std::endl;
       return 1;
   }
   // ...
 
}
 
« Последнее редактирование: Март 25, 2014, 11:32 от 8Observer8 » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #28 : Март 25, 2014, 12:07 »

А вот если писать свои классы исключений, то проблема с тем кто передаёт тексты ошибок - уходит:
"Вообще говоря" да, но все зависит от задачи. Для такого пионерского примерчика как у Вас исключения совершенно избыточны.

И главное - откуда возьмутся исключения, кто будет их генерить? Если каждый раз руками throw, то пользы немного. Обычно исключения испускают базовые ф-ции IO. Поскольку используются операторы >> и <<, то они и должны испускать. В std:: есть эта возможность, но ведь Вы работаете с Qt и вероятно будете использовать QDataStream. Как заставить его выбрасывать исключения?

Да, это может за рамками темы, но это реальный вопрос. А то в Вашем обзоре все слишком уж гладко   Улыбающийся
Записан
8Observer8
Гость
« Ответ #29 : Март 25, 2014, 13:15 »

Речь идёт о том, какой общий подход использовать. Понятно, что этот пример очень простой и достаточно было бы написать без всяких кодов ошибок. И в таком простом примере большинство ограничилось бы простым кодом:
Код
C++ (Qt)
   string outFileName = "output.txt";
   ofstream out;
   out.open( outFileName.c_str( ) );
   if ( !out.is_open( ) ) {
       cerr << "Error: could not open the file " << outFileName.c_str( ) << endl;
       in.close( );
       return 1;
   }
 

Я же хочу проанализировать разные подходы и выбрать один. Если не применять исключений, то нужно придерживаться одного из десятков способов обработки ошибок. Один из них Вы предложили. А вот функции из других библиотек с сишным подходом будут по-другому обрабатывать ошибки. Исключения же дают единообразный подход.

Если уж мы использовали подход с обработкой кодов ошибок с помощью функции showError(), то почему бы нам не использовать для этого примера свои классы исключений? Кода писать меньше, эти классы можно использовать повторно, код легко читать и изменять, а главное что это даёт единообразный подход к обработке пользовательских ошибок, как это сделано в C#, возможно и в Java (Java только начал изучать, поэтому не знаю, как там обстоят дела с исключениями)

Записан
Страниц: 1 [2] 3 4 ... 7   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.401 секунд. Запросов: 23.