Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 20.08.2017, 15:13   #1
KAMLS
Форумчанин
 
Регистрация: 09.04.2017
Сообщений: 598
По умолчанию Исключения

Здравствуйте!
Понимаю, что исключения придумали очень умные люди. Но поскольку я еще не настолько умный, то кое-что мне не понятно.
В приведенном ниже коде, я показал, что проще в метод класса поставить проверку величины значения, чем наводить тень на плетень этими исключениями))
Подскажите пожалуйста, в чем я не прав? Есть какие то ситуации где такими проверками не обойтись?
Код:
#include<iostream>
#include<conio.h>
using namespace std;
class Distance
{
private:
	int feet;
	float inches;
public:
	class InchesEx {};//класс исключений
	//---------------------------------
	Distance()//конструктор без аргументов
	{
		feet=0; 
		inches=0.0;
	}
	Distance(int ft, float in)//конструктор 2 аргумента
	{
		if(in>=12.0)
			throw InchesEx();
		feet=ft;
		inches=in;
	}
	//----------------------------------
	void getdist()//получить длину от пользователя
	{
		cout<<"\nEnter feet: ";
		cin>>feet;
		cout<<"\nEnter inches: ";
		cin>>inches;
		if(inches>=12.0)//если дюймы неправильные
			throw InchesEx();//генерировать исключение
		//Вот здесь можно поставить то что находится с 60 строки
		//catch(Distance::InchesEx)//поймать исключения
		//{
		//	cout<<"\nОшибка инициализации: "
		//		<<"\nзначение дюймов превышает предельно допустимое.";
		//}
	}
	//----------------------------------
	void showdist()//вывод рассстояний
	{
		cout<<feet<<"\'-"<<inches<<'\"';
	}
};
	////////////////////////////////////////////////////
	int main()
	{
		try
		{
			Distance dist1(17, 3.5);//конструктор 2 аргумента
			Distance dist2;//конструктор без аргументов
			dist2.getdist();//получить расстояние
			//вывести расстояния
			cout<<"\ndist1=";
			dist1.showdist();
			cout<<"\dist2=";
			dist2.showdist();
		}
		catch(Distance::InchesEx)//поймать исключения
		{
			cout<<"\nОшибка инициализации: "
				<<"\nзначение дюймов превышает предельно допустимое.";
		}
		cout<<endl;
		getch();
		return 0;
	}
KAMLS вне форума Ответить с цитированием
Старый 20.08.2017, 15:50   #2
eoln
Старожил
 
Аватар для eoln
 
Регистрация: 26.04.2008
Сообщений: 2,689
По умолчанию

Итак, программа просит ввести число, а пользователь пишет "одинадцать". И ошибка тут точно не в не удвоенном "н" )) Вот тут помогут исключения. Или пользователь просто напишет 5,6 вместо 5.6 или наоборот, исходя из его региональных предпочтений.

Можно и без них, тогда программа должна иметь ещё как минимум одну проверку - просить на вход строку, а затем строку пытаться перевести в число, и если не получится, то сообщить об ошибке.

Бывают случаи, когда проверить на всё нельзя/сложно. Например, пишет программа на диск файл, а диск 5 секунд назад украли или место там кончилось, потому что кто-то домашнее видео туда записал ))
eoln вне форума Ответить с цитированием
Старый 20.08.2017, 15:56   #3
Black Fregat
Программист
Участник клуба
 
Аватар для Black Fregat
 
Регистрация: 23.06.2009
Сообщений: 1,772
По умолчанию

Вы должны понимать, что пример предельно упрощён, чтобы показать суть работы с исключениями. Как и всякий другой инструмент, исключения - не серебряная пуля. В каждом конкретном случае разработчик сам решает, использовать исключения или нет.
Black Fregat вне форума Ответить с цитированием
Старый 20.08.2017, 17:52   #4
KAMLS
Форумчанин
 
Регистрация: 09.04.2017
Сообщений: 598
По умолчанию

Спасибо. Становится очень понятно.
В приведенном примере, условие в механизме исключения ориентированно на величину числа 12.0 дюймов.
Если я введу вместо числа строку, исключение сработает?
KAMLS вне форума Ответить с цитированием
Старый 20.08.2017, 17:56   #5
KAMLS
Форумчанин
 
Регистрация: 09.04.2017
Сообщений: 598
По умолчанию

Подзатупил)) программа то есть!)) проверить можно..)
Проверил.
Получилось вот так. Но ведь это не есть работа механизма исключения.
То есть условие то в любом случае прописывать надо...
Изображения
Тип файла: jpg кадр_27.jpg (101.8 Кб, 115 просмотров)

Последний раз редактировалось KAMLS; 20.08.2017 в 17:59.
KAMLS вне форума Ответить с цитированием
Старый 20.08.2017, 19:49   #6
waleri
Старожил
 
Регистрация: 13.07.2012
Сообщений: 6,493
По умолчанию

Цитата:
Сообщение от KAMLS Посмотреть сообщение
Есть какие то ситуации где такими проверками не обойтись
Нет, таких ситуаций нет, зато есть куча ситуаций, когда такие проверки будут неудобны.
Представьте себе, что вы вызываете функцию A(), она вызывает B1(), B2() и B3().
Каждая из B функций вызывает несколько C() функций. На каждом этапе может возникнуть ошибка, поэтому надо на всех этапах проверять коды ошибки, чтобы вернуть их наверх по цепочке. В итоге все функции должны делать одну и ту же проверку, только потому что в недрах функции Z() может произойти реальная ошибка.

Много проще в A() вставить try/catch а в Z() сделать throw.

Ну и не на последнем месте - exception-ы следует использовать именно для исключительных ситуаций. Не правильный потребительский ввод таковой ситуацией не является, но это уже дело вкуса.
waleri на форуме Ответить с цитированием
Старый 21.08.2017, 02:08   #7
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

Цитата:
Сообщение от waleri Посмотреть сообщение
Нет, таких ситуаций нет, зато есть куча ситуаций, когда такие проверки будут неудобны.
Представьте себе, что вы вызываете функцию A(), она вызывает B1(), B2() и B3().
Каждая из B функций вызывает несколько C() функций. На каждом этапе может возникнуть ошибка, поэтому надо на всех этапах проверять коды ошибки, чтобы вернуть их наверх по цепочке. В итоге все функции должны делать одну и ту же проверку, только потому что в недрах функции Z() может произойти реальная ошибка.

Много проще в A() вставить try/catch а в Z() сделать throw.
рецепт, как писать плохой код?

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

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

будь то ассерт-проверка,
бросок исключения,
либо код ошибки.


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

например подключение к базе данных.
код написан правильно.
однако это не гарантирует успешное подключение.
база данных может вернуть: "сервер переполнен", например.

пользовательский код соответственно,
не сможет выполнить собственную бизнес-логику,
и как следствие корректно отработать собственную процедуру.

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

важно понимать:
что ловить эксепшоны нужно по месту вызовов потенциально сбойных функций.

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

вы в своём A() поймаете эксепшон, который вылетел из Z()
но сделать уже ничего не сможете.
потому что A() ничего не знает ни о Z(),
ни о других буковках английского алфавита.

но если вы попытаетесь заставлять A() знать про Z()
и другие буковки английского алфавита,
то получите эпическое нарушение инкапсуляции:
потерю контроля за сложностью проекта.
_Bers вне форума Ответить с цитированием
Старый 21.08.2017, 08:41   #8
KAMLS
Форумчанин
 
Регистрация: 09.04.2017
Сообщений: 598
По умолчанию

Цитата:
Сообщение от _Bers Посмотреть сообщение
важно понимать:
что ловить эксепшоны нужно по месту вызовов потенциально сбойных функций.

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

вы в своём A() поймаете эксепшон, который вылетел из Z()
но сделать уже ничего не сможете.
потому что A() ничего не знает ни о Z(),
ни о других буковках английского алфавита.

но если вы попытаетесь заставлять A() знать про Z()
и другие буковки английского алфавита,
то получите эпическое нарушение инкапсуляции:
потерю контроля за сложностью проекта.
То есть всё-таки лучше пользоваться объектами класса, в методах которого учтены все возможные варианты развития ситуаций, и по каждому варианту есть своя, именованная реакция?
А исключения оставить только на случай каких-то общих стандартных сбоев?
KAMLS вне форума Ответить с цитированием
Старый 21.08.2017, 09:26   #9
waleri
Старожил
 
Регистрация: 13.07.2012
Сообщений: 6,493
По умолчанию

Цитата:
Сообщение от _Bers Посмотреть сообщение
в действительности каждая функция
должна выполнять проверки всех своих входных аргументов,
Будьте любезны указать в моем посте где я сказал, что этого делать не следует.

Цитата:
Сообщение от _Bers Посмотреть сообщение
в случае обнаружения любых сбоев,
функция должна каким то образом предупредить
Будьте любезны указать в моем посте где я сказал, что этого делать не следует.
Собственно мы обсуждаем как именно это сделать - через код ошибки или через исключение.


Цитата:
Сообщение от _Bers Посмотреть сообщение
пользовательский код соответственно,
не сможет выполнить собственную бизнес-логику,
Пользовательский код - это функция A() где собственно я и сказал, что должен быть try/catch блок.
Цитата:
Сообщение от _Bers Посмотреть сообщение
что ловить эксепшоны нужно по месту вызовов потенциально сбойных функций.
Не обязательно. Все суть исключений в том, что они могут перепрыгивать.
Если А() это самый верхний уровень, М() это открытие базы данных а Z() это открытие файла то мне на уровне А() фиолетово будет ли у меня FileNotFoundException или CannotOpenDatabase - и в том и в другом случае я просто информирую потребителя и еду дальше. Далее, если М() может справиться с ситуацией, то нигде нет запрета перехватить нужное исключение и отработать по запасному варианту.

Цитата:
Сообщение от _Bers Посмотреть сообщение
вы в своём A() поймаете эксепшон, который вылетел из Z()
но сделать уже ничего не сможете.
А что я можно сделать? Очевидно речь идет о случаях, когда кроме как показать сообщение об ошибке делать нечего. Еще раз: - исключения - это для исключительных ситуаций.

Цитата:
Сообщение от _Bers Посмотреть сообщение
но если вы попытаетесь заставлять A() знать про Z()
Я заставляю A() знать про какой-то базовый класс исключения, который должен содержать код и место возникновения ошибки. Исключительно уровень А() решает когда и как показывать сообщения об ошибках. Уровень Z() не должен знать есть у нас логирование, окна, отладчики и иже с ними. Уровень Z() кричит "не могу открыть файл" (хотя это плохой пример, ну да ладно) и этому уровню фиолетово кто и как это будет обрабатывать.
waleri на форуме Ответить с цитированием
Старый 21.08.2017, 18:05   #10
Croessmah
Вредный кошак
Участник клуба
 
Аватар для Croessmah
 
Регистрация: 14.10.2012
Сообщений: 1,159
По умолчанию

Одно из достоинств исключений - легче поддерживать инварианты классов.
Croessmah вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Исключения c# CROWN C# (си шарп) 3 21.12.2014 18:29
Исключения в Qt iukash Qt и кроссплатформенное программирование С/С++ 6 16.04.2011 18:54
Исключения C++ Impuls1989 Помощь студентам 2 04.03.2011 00:51
Исключения yurik1982 Фриланс 9 16.02.2010 00:34
Исключения Rifler Общие вопросы Delphi 5 12.11.2008 00:29