Ответ 1
Книга немного расплывчата. Это не столько "ошибка времени выполнения", сколько поведение undefined, которое проявляется во время выполнения. Это означает, что все может случиться. Но ошибка строго связана с вами, а не с выполнением программы, и на самом деле невозможно и неразумно даже говорить о выполнении программы с поведением undefined.
В С++ нет ничего, что защищало бы вас от ошибок программирования, в отличие от Java.
Как говорит @sftrabbit, std::vector
имеет альтернативный интерфейс .at()
, который всегда дает правильную программу (хотя она может генерировать исключения), и, следовательно, о котором можно рассуждать.
Позвольте мне повторить пункт с примером, потому что я считаю, что это важный фундаментальный аспект С++. Предположим, мы читаем целое число от пользователя:
int read_int()
{
std::cout << "Please enter a number: ";
int n;
return (std::cin >> n) ? n : 18;
}
Теперь рассмотрим следующие три программы:
Опасный: Правильность этой программы зависит от пользовательского ввода! Это не обязательно неверно, но это небезопасно (до такой степени, что я бы назвал его сломанным).
int main()
{
int n = read_int();
int k = read_int();
std::vector<int> v(n);
return v[k];
}
Безоговорочно правильно: Независимо от того, что вводит пользователь, мы знаем, как ведет себя эта программа.
int main() try
{
int n = read_int();
int k = read_int();
std::vector<int> v(n);
return v.at(k);
}
catch (...)
{
return 0;
}
Разумный: Вышеприведенная версия с .at()
неудобна. Лучше проверить и предоставить обратную связь. Поскольку мы выполняем динамическую проверку, неконтролируемый векторный доступ на самом деле гарантированно хорош.
int main()
{
int n = read_int();
if (n <= 0) { std::cout << "Bad container size!\n"; return 0; }
int k = read_int();
if (k < 0 || k >= n) { std::cout << "Bad index!\n"; return 0; }
std::vector<int> v(n);
return v[k];
}
(Мы игнорируем возможность того, что построение вектора может вызвать исключение из его собственных.)
Мораль заключается в том, что многие операции на С++ являются небезопасными и только условно правильными, но от программиста ожидается, что вы сделаете необходимые проверки раньше времени. Язык не делает этого для вас, и поэтому вы не платите за него, но вы должны помнить об этом. Идея состоит в том, что вам все равно придется обрабатывать условия ошибки, и поэтому вместо того, чтобы выполнять дорогостоящую, неспецифическую операцию на уровне библиотеки или языка, ответственность остается за программистом, который находится в лучшем положении для интеграции проверки в код, который должен быть записан в любом случае.
Если бы я хотел быть преувеличенным, я бы сравнил этот подход с Python, который позволяет писать невероятно короткие и правильные программы без какой-либо пользовательской обработки ошибок. Оборотная сторона заключается в том, что любая попытка использовать такую программу, которая немного отличается от того, что предлагает программист, оставляет вам неспецифическую, трудночитаемую исключение и трассировку стека, а также небольшие рекомендации относительно того, что вы должны были сделать лучше. Вы не обязаны писать какую-либо обработку ошибок, и часто обработка ошибок не записывается. (Я не могу отличить С++ от Java, потому что, хотя Java вообще безопасен, мне еще предстоит увидеть короткую Java-программу.) </rantmode>