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

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

Страниц: 1 [2] 3 4 5   Вниз
  Печать  
Автор Тема: Стратегия обработки ошибок пользователя с помощью собственных классов исключений  (Прочитано 53996 раз)
8Observer8
Гость
« Ответ #15 : Октябрь 19, 2014, 23:09 »

В моём примере есть функция divide(a, b), где a и b должны быть в диапазоне [-1000, 1000]. Если один из параметров превысил этот диапазон, то функция выбросит исключение с текстом:
Цитировать
Error: values must be from the range [-1000, 1000] in the function Calculator::divide()

Допустим в моём проекте 10 классов, и в каждой по несколько функций, которые должны следить за диапазоном своих аргументов. Мне при написании этих функций достаточно выбросить после проверки исключение:
Код
C++ (Qt)
throw OutOfRange<int>( beginOfRange,
                                 endOfRange,
                                 functionName );

Я могу так же легко написать любое исключение. Мне достаточно будет унаследовать его от LogicError. К примеру, могу написать исключение EmptyError, которое будет содержать текст, что входной аргумент пуст. Допустим, я разрабатываю функцию printArray, которая принимает массив и выбрасывает исключение EmptyError, если входной аргумент пуст:

Output:
Цитировать
Error: empty argument in the function printArray()

main.cpp
Код
C++ (Qt)
#include <QVector>
#include <iostream>
#include "freeFunctions.h"
 
int main()
{
   QVector<int> arr;
 
   try {
       printArray( arr );
   } catch ( const LogicError &e ) {
       std::cerr << e.what() << std::endl;
       return 1;
   } catch ( ... ) {
       std::cerr << "Error: unknown expection" << std::endl;
       return 1;
   }
 
   return 0;
}
 

freeFunctions.h
Код
C++ (Qt)
#ifndef FREEFUNCTIONS_H
#define FREEFUNCTIONS_H
 
#include <QVector>
#include <iostream>
#include "EmptyArgument.h"
 
void printArray( const QVector<int> &arr )
throw ( EmptyArgument );
 
#endif // FREEFUNCTIONS_H
 

freeFunctions.cpp
Код
C++ (Qt)
#include "freeFunctions.h"
 
void printArray(const QVector<int> &arr )
   throw ( EmptyArgument )
{
   std::string functionName = "printArray()";
 
   if ( arr.isEmpty() ) {
       throw EmptyArgument( functionName );
   }
 
   for ( std::size_t i = 0; i < arr.size(); ++i ) {
       std::cout << arr[i] << std::endl;
   }
}
 

EmptyArgument.h
Код
C++ (Qt)
#ifndef EMPTYARGUMENT_H
#define EMPTYARGUMENT_H
 
#include <string>
#include "LogicError.h"
 
class EmptyArgument : public LogicError
{
public:
   EmptyArgument( const std::string &functionName ) :
       LogicError( functionName )
   {
       m_message = "Error: empty argument in the "
               "function " + m_functionName;
   }
};
 
#endif // EMPTYARGUMENT_H
 

« Последнее редактирование: Октябрь 19, 2014, 23:18 от 8Observer8 » Записан
8Observer8
Гость
« Ответ #16 : Октябрь 20, 2014, 08:13 »

Статья увеличилась. Следующий раздел будет называться: Проверки: открыт ли файл, удачна ли запись, удачно ли чтение
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #17 : Октябрь 20, 2014, 08:49 »

В моём примере есть функция divide(a, b), где a и b должны быть в диапазоне [-1000, 1000].
Где Вы видели такую задачу? Значит 1000 можно делить на что-то, а 1001 уже нельзя - это с какой стати? Если стратегия/концепция (что Вы хотели показать) нуждается в столь синтетических примерах - грош ей цена.

Допустим в моём проекте 10 классов, и в каждой по несколько функций, которые должны следить за диапазоном своих аргументов. Мне при написании этих функций достаточно выбросить после проверки исключение:
Код
C++ (Qt)
throw OutOfRange<int>( beginOfRange,
                                 endOfRange,
                                 functionName );
 
Вероятно имелось ввиду что черновая работа (печать строки ошибки и.т.п.) собрана в классе исключения, и ее не придется писать 10 раз. Так нормальный программист решил бы это без всяких книжек (с завлекательным названием "профессионал") просто-напросто создав ф-цию, напр
Код
C++ (Qt)
// использование
if (!ValidRange <int>(value, MIN_VAL, MAX_VAL)) return false;
..
// ф-ция проверки
template <class T>
bool ValidRange( T val, T minV, T maxV, bool useException = true )
{
if (val >= minV && val <= maxV) return true;
std::string errText;
 .. // печатаем ошибку
 
if (useException)
 throw std::out_of_range(errText);
else
 printf("error: %s\n", errText.c_str());  // для отладки
return false;
}
 
Чего не хватает? Зачем выдумывать классы раздувая текст на ровном месте?
Записан
8Observer8
Гость
« Ответ #18 : Октябрь 20, 2014, 09:18 »

Цитировать
Где Вы видели такую задачу? Значит 1000 можно делить на что-то, а 1001 уже нельзя - это с какой стати? Если стратегия/концепция (что Вы хотели показать) нуждается в столь синтетических примерах - грош ей цена.
Пока не придумал подходящего примера
Записан
8Observer8
Гость
« Ответ #19 : Октябрь 20, 2014, 09:49 »

Давайте пока забудем про OutOfRange. Я может пока вообще удалю этот пример до лучших времён. В книге был пример с проверками файла на открытие чтение и т.д. А OutOfRange это я уже развил, а пример оказался неудачный

Теперь о файлах и собственных классах исключений

Если файл не открывается, то выбрасывается исключение FileOpenError с текстом, к примеру:
Цитировать
Error: unable to open the file "input.txt" in the "readData()"

Если из файла невозможно прочитать, то - FileReadError с тектом:
Цитировать
Error: unable to read the file "input.txt" in the "readData()"

Если диск переполнен и невозможно записать, то - FileWriteError с текстом:
Цитировать
Error: unable to write to the file "input.txt" in the "readData()"

Все выше перечисленные исключения наследуются от FileError, поэтому мы можем все три исключения отлавливать так:
Код
C++ (Qt)
   try {
       // ...
   }
   catch ( const FileError &e ) {
       std::cerr << e.what( ) << std::endl;
       return 1;
   } catch ( ... ) {
       std::cerr << "Error: unknown exception" << std::endl;
       return 1;
   }
 

Исключение EmptyArgument выбрасывается, когда входные данные пустые и наследуется от LogicError

Следующий пример читает имена и фамилии из файла, заполняет массив объектов типа Person и выводит имена на экран:

main.cpp
Код
C++ (Qt)
#include <iostream>
#include <vector>
#include <QString>
#include "freeFunctions.h"
#include "Person.h"
 
int main( )
{
   // Person array for saving
   Person david( "David", "White");
   Person ivan( "Ivan", "Green" );
   std::vector<Person> persons;
   persons.push_back( david );
   persons.push_back( ivan );
 
   try {
       // Parse the person array to the string content
       QString content;
       parsePersonsToStrContent( persons, content );
 
       // Save the string content to the file
       QString fileName = "file.txt";
       writeData( fileName, content );
 
       // Read the string content from the file
       QString readContent;
       readData( fileName, readContent );
 
       // Parse the string content to the person array
       std::vector<Person> readPersons;
       parseContentToPersons( readContent, readPersons );
 
       // Print the person array on the screen
       printData( readPersons );
   } catch ( const LogicError &e ) {
       std::cerr << e.what( ) << std::endl;
       return 1;
   } catch ( const FileError &e ) {
       std::cerr << e.what( ) << std::endl;
       return 1;
   } catch ( ... ) {
       std::cerr << "Error: unknown exception" << std::endl;
       return 1;
   }
 
   return 0;
}
 

Person.h
Код
C++ (Qt)
#ifndef PERSON_H
#define PERSON_H
 
#include <QString>
 
class Person {
public:
 
   Person( const QString &firstName = "",
           const QString &lastName = "" ) :
       m_firstName( firstName ),
       m_lastName( lastName )
   {
 
   }
 
   QString firstName( ) const
   {
       return m_firstName;
   }
 
   QString lastName( ) const
   {
       return m_lastName;
   }
 
   void setFirstName( const QString &firstName )
   {
       m_firstName = firstName;
   }
 
   void setLastName( const QString &lastName )
   {
       m_lastName = lastName;
   }
 
private:
   QString m_firstName;
   QString m_lastName;
};
 
#endif // PERSON_H
 

freeFunctions.h
Код
C++ (Qt)
#ifndef FREEFUNCTIONS_H
#define FREEFUNCTIONS_H
 
#include <vector>
 
#include <QString>
 
#include "FileOpenError.h"
#include "FileReadError.h"
#include "FileWriteError.h"
#include "EmptyArgument.h"
#include "Person.h"
 
void readData( const QString &fileName, QString &content )
throw ( EmptyArgument, FileOpenError, FileReadError );
 
void parseContentToPersons( const QString &content,
                           std::vector<Person> &persons )
throw ( EmptyArgument );
 
void parsePersonsToStrContent( const std::vector<Person> &persons,
                              QString &content)
throw ( EmptyArgument );
 
void writeData( const QString &fileName,
               const QString &content )
throw ( EmptyArgument, FileOpenError, FileWriteError );
 
void printData( const std::vector<Person> &persons )
throw ( EmptyArgument );
 
#endif // FREEFUNCTIONS_H
 

freeFunctions.cpp
Код
C++ (Qt)
#include <iostream>
#include <string>
#include <QFile>
#include <QRegExp>
#include <QTextStream>
#include <QDebug>
#include "freeFunctions.h"
 
void readData(const QString &fileName, QString &content )
throw ( EmptyArgument, FileOpenError, FileReadError )
{
   std::string functionName = "readData()";
 
   // Check argument
   if ( fileName.isEmpty( ) ) {
       throw EmptyArgument( functionName );
   }
 
   // Open the input file for reading
   QFile file( fileName );
   if( !file.open( QIODevice::ReadOnly ) ) {
       throw FileOpenError( fileName.toStdString( ), functionName );
   }
 
   // Read the content from the file
   QByteArray data = file.readAll( );
   if ( data.isEmpty( ) ) {
       throw FileReadError( fileName.toStdString( ), functionName );
   }
 
   content = QString( data );
}
 
void parseContentToPersons( const QString &content, std::vector<Person> &persons )
throw ( EmptyArgument )
{
   std::string functionName = "parseContentToPersons()";
 
   // Check the input argument
   if ( content.isEmpty( ) ) {
       throw EmptyArgument( functionName );
   }
 
   QRegExp regExp("(\\w+) (\\w+)");
   int pos = 0;
   while ( ( pos = regExp.indexIn( content, pos ) ) != -1 ) {
       QString firstName = regExp.cap( 1 );
       QString lastName = regExp.cap( 2 );
       Person person( firstName, lastName );
       persons.push_back( person );
       pos += regExp.matchedLength( );
   }
}
 
void parsePersonsToStrContent( const std::vector<Person> &persons,
                              QString &content)
throw ( EmptyArgument )
{
   std::string functionName = "parsePersonsToStrContent()";
 
   // Check the input argument
   if ( persons.empty( ) ) {
       throw EmptyArgument( functionName );
   }
 
   for ( std::size_t i = 0; i < persons.size( ); ++i ) {
       QString firstName = persons[i].firstName( );
       QString lastName = persons[i].lastName( );
       QString line = QString( "%1 %2\n" ).arg( firstName ).arg( lastName );
       content.append( line );
   }
}
 
void writeData( const QString &fileName, const QString &content )
throw ( EmptyArgument, FileOpenError, FileWriteError )
{
   std::string functionName = "writeData()";
 
   // Check arguments
   if ( fileName.isEmpty( ) || content.isEmpty( ) ) {
       throw EmptyArgument( functionName );
   }
 
   // Open the output file for writing
   QFile file( fileName );
   if ( !( file.open( QIODevice::WriteOnly ) ) ) {
       throw FileOpenError( fileName.toStdString( ), functionName );
   }
 
   // Write data to the output file
   QTextStream stream( &file );
   stream << content;
   if ( stream.status() != QTextStream::Ok ) {
       throw FileWriteError( fileName.toStdString( ), functionName );
   }
}
 
void printData( const std::vector<Person> &persons )
throw ( EmptyArgument )
{
   std::string functionName = "printData()";
 
   // Check the input argument
   if ( persons.empty( ) ) {
       throw EmptyArgument( functionName );
   }
 
   // Print data
   for ( std::size_t i = 0; i < persons.size( ); ++i ) {
       std::cout << "First Name: " << persons[i].firstName( ).toStdString( ) << std::endl;
       std::cout << "Last Name: " << persons[i].lastName( ).toStdString( ) << std::endl;
       std::cout << std::endl;
   }
}
 

FileError.h
Код
C++ (Qt)
#ifndef FILEERROR_H
#define FILEERROR_H
 
#include <string>
#include <stdexcept>
 
class FileError : public std::runtime_error
{
public:
 
   FileError( const std::string &fileName,
              const std::string &functionName) :
       std::runtime_error( "" ),
       m_message( "" ),
       m_fileName( fileName ),
       m_functionName( functionName )
   {
 
   }
 
   virtual ~FileError( ) throw( )
   {
 
   }
 
   virtual const char *what() const throw( )
   {
       return m_message.c_str( );
   }
 
   std::string message( ) const
   {
       return m_message;
   }
 
protected:
   std::string m_message;
   std::string m_fileName;
   std::string m_functionName;
};
 
#endif // FILEERROR_H
 

FileOpenError.h
Код
C++ (Qt)
#ifndef FILEOPENERROR_H
#define FILEOPENERROR_H
 
#include <string>
#include "FileError.h"
 
class FileOpenError : public FileError {
public:
 
   FileOpenError( const std::string &fileName,
                  const std::string &functionName) :
       FileError( fileName, functionName )
   {
       m_message = "Error: unable to open the file \"" +
               m_fileName + "\" in the function \"" +
               m_functionName + "\"";
   }
};
 
#endif // FILEOPENERROR_H
 

FileReadError.h
Код
C++ (Qt)
#ifndef FILEREADERROR_H
#define FILEREADERROR_H
 
#include <string>
#include "FileError.h"
 
class FileReadError : public FileError {
public:
 
   FileReadError( const std::string &fileName,
                  const std::string &functionName ) :
       FileError( fileName, functionName )
   {
       m_message = "Error: unable to read the file \"" + m_fileName +
               "\" in the function \"" + m_functionName + "\"";
   }
};
 
#endif // FILEREADERROR_H
 

FileWriteError.h
Код
C++ (Qt)
#ifndef FILEWRITEERROR_H
#define FILEWRITEERROR_H
 
#include <string>
#include "FileError.h"
 
class FileWriteError : public FileError {
public:
 
   FileWriteError( const std::string &fileName,
                   const std::string &functionName ) :
       FileError( fileName, functionName )
   {
       m_message = "Error: unable to write to the file " +
               m_fileName + " in the function " + m_functionName;
   }
};
 
#endif // FILEWRITEERROR_H
 

EmptyArgument.h
Код
C++ (Qt)
#ifndef EMPTYARGUMENT_H
#define EMPTYARGUMENT_H
 
#include <string>
#include "LogicError.h"
 
class EmptyArgument : public LogicError {
public:
 
   EmptyArgument( const std::string &functionName ) :
       LogicError( functionName )
   {
       m_message = "Error: empty argument in the "
               "function " + m_functionName;
   }
};
 
#endif // EMPTYARGUMENT_H
 

LogicError.h
Код
C++ (Qt)
#ifndef LOGICERROR_H
#define LOGICERROR_H
 
#include <string>
#include <stdexcept>
 
class LogicError : public std::logic_error
{
public:
 
   LogicError( const std::string &functionName ) :
       std::logic_error( "" ),
       m_functionName( functionName ),
       m_message( "" )
   {
 
   }
 
   virtual ~LogicError( ) throw( )
   {
 
   }
 
   virtual const char *what( ) const throw( )
   {
       return m_message.c_str( );
   }
 
   std::string message( ) const
   {
       return m_message;
   }
 
protected:
   std::string m_functionName;
   std::string m_message;
};
 
#endif // LOGICERROR_H
 
Записан
8Observer8
Гость
« Ответ #20 : Октябрь 20, 2014, 10:00 »

Посмотрите сейчас на мою статью. Она стала лучше
Записан
Bepec
Гость
« Ответ #21 : Октябрь 20, 2014, 11:36 »

Огроооомный минус перебивающий все плюсы - что за ересь у вас в архиве с исходниками?
Записан
8Observer8
Гость
« Ответ #22 : Октябрь 20, 2014, 15:11 »

То что в проекте становится побольше классов, после введения этой концепции, так это не проблема, а преимущество. Разделяй и властвуй!
Записан
Bepec
Гость
« Ответ #23 : Октябрь 20, 2014, 15:35 »

Я про то, что у вас в архиве лежит хренова туча хрен знает какого кода с пустыми папками и без пояснений...
Записан
8Observer8
Гость
« Ответ #24 : Октябрь 20, 2014, 22:07 »

Значит это не мой архив, так как я никаких архивов, в этой теме, не прикреплял
« Последнее редактирование: Октябрь 20, 2014, 22:11 от 8Observer8 » Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #25 : Октябрь 20, 2014, 22:19 »

Это даже близко не статья..(
В статье самое главное - это Заключение (Conclusions) (поскольку, по большому счёту, только его и читают)
А заключение должно быть, как женское нижнее бельё - Короткое, прозрачное и возбуждающее)

А здесь этим даже и не пахнет)
« Последнее редактирование: Октябрь 20, 2014, 22:21 от m_ax » Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
gil9red
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 1805



Просмотр профиля WWW
« Ответ #26 : Октябрь 20, 2014, 23:12 »

Значит это не мой архив, так как я никаких архивов, в этой теме, не прикреплял

Первое сообщение темы имеет ссылку на архив на яндексе
Записан

Bepec
Гость
« Ответ #27 : Октябрь 21, 2014, 07:01 »

Бгг... вот это человек... У него в статье прячется вражеский архив, а он и не знает Веселый
Записан
8Observer8
Гость
« Ответ #28 : Октябрь 21, 2014, 08:54 »

Спасибо за замечания! Над заключением подумаю

По поводу архива, то там всё нормально. Я этот код скачал отсюда: ссылка Число в названии папки означает номер главы. В некоторых главах книги нет примеров с кодом, поэтому и написано "empty". Вот содержимое папки:


Записан
qate
Супер
******
Offline Offline

Сообщений: 1175


Просмотр профиля
« Ответ #29 : Октябрь 21, 2014, 09:39 »

Функция printArray принимает массив и выбрасывает исключение EmptyError, если входной аргумент пуст:

низа чтобы не стал пользоваться такой функцией

в концепции qt исключения получаются как лишними - везде ходят события и отложенный результат
Записан
Страниц: 1 [2] 3 4 5   Вверх
  Печать  
 
Перейти в:  


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