На этом шаге мы рассмотрим обработку ошибок в STL.
Ошибки случаются, хотим мы того или нет. Они могут быть обусловлены как действиями программы (а точнее, программиста), так и контекстом или рабочей средой программы (например, нехваткой памяти). Обе разновидности ошибок обрабатываются при помощи исключений (начальные сведения об исключениях приводятся, начиная с шага 45). Данные шаги посвящены принципам обработки ошибок и исключений в STL.
При проектировании STL главным приоритетом была максимальная производительность, а не безопасность. Проверка ошибок требует времени, поэтому в STL она практически не выполняется. Если вы умеете программировать без ошибок, все замечательно, а если нет - дело кончится катастрофой. Перед включением библиотеки STL в стандартную библиотеку C++ обсуждался вопрос о том, не нужно ли расширить обработку ошибок. Большинство высказались против по двум причинам.
В результате проверка ошибок в STL возможна, но не обязательна.
В спецификации стандартной библиотеки C++ указано, что любое использование STL, нарушающее предварительные условия, приводит к непредсказуемому поведению. Следовательно, при недействительном индексе, итераторе или интервале может произойти все что угодно. Если не использовать безопасную версию STL, обычно дело кончается нарушением защиты памяти с неприятными побочными эффектами и даже сбоем программы. В некотором смысле применение библиотеки STL так же чревато ошибками, как применение указателей в языке С. Найти такие ошибки иногда бывает очень трудно, особенно если нет безопасной версии STL.
В частности, для нормальной работы STL должны выполняться перечисленные ниже условия.
//--------------------------------------------------------------------------- #include <vcl.h> #include <iostream> #include <vector> #include <algorithm> #include <conio.h> //необходимо для getch() #pragma hdrstop //--------------------------------------------------------------------------- #pragma argsused using namespace std; std::string ToRus(const std::string &in) { char *buff = new char [in.length()+1]; CharToOem(in.c_str(),buff); std::string out(buff); delete [] buff; return out; } template <class T> inline void PRINT_ELEMENTS (const T& coll, const char* optcstr="") { typename T::const_iterator pos; std::cout << ToRus(optcstr); for (pos=coll.begin(); pos!=coll.end(); ++pos) { std::cout <<*pos <<' '; } std::cout << std::endl; } int main(int argc, char* argv[]) { vector<int> coll1; // Пустая коллекция vector<int> coll2; // Пустая коллекция // ОШИБКА: начало находится за концом интервала vector<int>::iterator pos = coll1.begin(); reverse (++pos,coll1.end()); // Вставка элементов со значениями от 1 до 9 в coll2 for (int i=1; i<=9; ++i) { coll2.push_back(i); } PRINT_ELEMENTS(coll2,"Инициализация coll2:\n"); // ОШИБКА: перезапись несуществующих элементов copy (coll2.begin(), coll2.end(), // Источник coll1.begin()); //Приемник PRINT_ELEMENTS(coll1,"Значения coll1:\n"); // ОШИБКА: // - перепутаны коллекции // - перепутаны begin() и end() copy (coll1.begin(), coll2.end(), // Источник coll1.end()); PRINT_ELEMENTS(coll1,"Значения coll1:\n"); cout << endl; getch(); return 0; } //---------------------------------------------------------------------------
Результат работы программы показать не можем, так как было выдано сообщение об ошибке на этапе выполнения программы.
Отметим еще раз, что все указанные ошибки происходят не на стадии компиляции, a во время выполнения программы, поэтому они приводят к непредсказуемым последствиям.
Библиотека STL предоставляет массу возможностей для ошибок. Она вовсе не обязана защищать вас от самого себя, поэтому желательно (по крайней мере, на время разработки программы) использовать безопасную версию STL. Первая безопасная версия STL была разработана Кеем Хорстманом (Cay Horstmann).
К сожалению, многие поставщики предоставляют версию STL, основанную на исходном варианте кода, в котором обработка ошибок не предусмотрена. Впрочем, ситуация постепенно улучшается. Современная безопасная версия STL распространяется бесплатно практически для всех платформ (http://www.stlport.org/).
На следующем шаге мы рассмотрим обработку исключений.