Nicknu
@Nicknu

Try-catch-throw. Как понять эту схему?

Никак не могу понять смысл и принцип работы Try-catch-throw. Читал в книге - не в вник, шастал по сайтам из Google - не вник. У меня есть ряд вопросов относительно этих (или этого) блока. Может быть, здесь есть хорошо умеющие с этим управляться люди, которые не поленятся объяснить.
1. Допустим, у меня есть 3 вектора, в которых хранятся имена. Пользователю предложено ввести кол-во векторов, данные в которых он хочет увидеть (это специально, чтобы узнать, как работают эти блоки).
код с вектором
vector<string> names(3); //вектор
	names[0] = "Nameone";
	names[1] = "Nametwo";
	names[2] = "Namethree"; 
        //ввод
	cout << "Введите, сколько нужно вывести данных из вектора names\n";
	int inames = 0; //
        cin >> inames;
	cout << "\n";
        //то, что вызывает недопонимание
	try {
			for (int i = 0; i < inames; i++) {
				cout << names[i] << endl; }

		}
	catch (...) {
		cout << "Ошибка 1. Не найден введенный вектор."; }

Например, я ввожу 5 - в итоге сообщается об ошибке системой Windows (так и без try происходит), а не программой. Я думал, что try предназначен именно для этого, чтобы, например, если пользователь введет значение, ведущее к ошибке, программа не завершалась, а сообщала об ошибке. Думается мне, что представление моё неправильно.
2. Можно простой пример работы try-catch-throw, где в тип string вводится int и сообщается об ошибке?
3. Если у вас есть педагогический талант, не могли бы вы объяснить, верно ли мое представление об этой функции и где можно было бы узнать о ней поподробнее (новичок).
  • Вопрос задан
  • 466 просмотров
Пригласить эксперта
Ответы на вопрос 2
@nirvimel
Вы называете одним словом "ошибка" несколько совершенно различных вещей, не связанных между собой:
  1. Синтаксическая ошибка в исходном коде. "где в тип string вводится int и сообщается об ошибке" - это невозможно в принципе, так как ваш исходный код, в котором нарушено соответствие типов, не является валидной программой (все равно что оставить незакрытую скобку), компилятор не сможет скомпилировать из него никакой бинарный исполнимый файл просто потому, что видит бессмыслицу в таком исходнике.
  2. Исключительная ситуация (exception) во время выполнения. Она всегда предусмотрена кодером (этим она и отличается). Например я пишу функцию, которая должна делить одно число на другое, я предполагаю, что кто-то (типа меня же) может использовать эту функцию неправильно и передать ноль в качестве делителя. Я хочу, чтобы такому пользователю прилетел (по голове) exception, красноречиво сообщающий о том, что так делать не стоит. Для этого я пишу
    if (denominator == 0) { throw std::invalid_argument( "НЕ НАДО ТАК!" ); }
    . Теперь, если мне нужно выполнить какой-то кусок кода, в котором есть вызовы функций, из которых могут вылетать исключения, и я хочу как-то локализовать эту проблему и обезопасить от этого остальную программу, то я пишу
    try { divide(x, 0); } catch (const std::invalid_argument& e) { /* Я все понял, я так больше не буду. */ }
    .
  3. Undefined behavior - это результат не предусмотренной никем ситуации во время выполнения. Например, я заб(ы/и)л на то, что кто-то может передать ноль в мою функцию в качестве делителя и пишу int divide(int a, int b) { return a / b; }. И однажды это происходит, кто-то (да я же сам) передает туда ноль и... Что должно произойти в этой ситуации? Я не знаю, CPU не знает, компилятор об этом не позаботился, ОС тоже не знает, но на всякий случай она прихлопнет весь процесс целиком и (возможно) напишет в консоль что-то типа segmentation fault.
    А что, если я буду вызывать такую подозрительную функцию из блока try-catch? - Да ничего это не меняет. try-catch ловит только преднамеренно брошенные исключения в ситуации, когда возможность возникновения ошибки была предусмотрена кодером. try-catch ничем не может помочь против undefined behavior потому, что предусматривать возможные ошибки во время выполнения - это задача кодера, а не компилятора, который занимается только контролем соответствия типов и формальной корректности программы.


Если вам не по душе концепция undefined behavior, то переходите на Java или .NET, там компиляторы сами добавляют все необходимые (и обходимые) проверки ценой снижения быстродействия вашей программы.
Ответ написан
@huwesu
Конкретно в этом случае вы можете легко проверять условным оператором, а не вышли ли вы за пределы массива. До цикла, разумеется - там быстрее будет работать.
Я бы тут не полагался бы на исключения.

Ну а конкретно про ваш случай:

С/С++ являются инструментами, в которых легко отстрелить себе ногу.
В чем вы только что и убедились.

Компилятор предполагает, что разработчик ЗНАЕТ, что делает и не проверяет никак выход за пределы массива. Вылет вы словили вообще совершенно случайно. И это везение что вы словили падение так просто и сразу. Скорее всего там был Segmentation Fault?

Это особенность С/С++ - там за все такие косяки отвечает сам программист.

Дело в том, что изначально С/С++ заточены на скорость, а постоянные проверки выхода за пределы массива (вектора) заметно замедляют работу программы во многих случаях.

Однако вы можете изменить такое поведение компилятора.
Для этого вам нужно задать компилятору некие параметры.
Какие именно - не подскажу, компиляторы разные.

Но у всех мне известных компиляторов С/С++ можно указать, чтобы компилятор делал эти самые дополнительные проверки, которые вы тут ожидаете.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы