Я привык к Delphi Платформа VCL, где TStreams выдают исключения на ошибках (например, файл, не найденный, полный диск). Я портирую некоторый код для использования C++ STL и ловился iostreams, НЕ выдающим исключения по умолчанию, но устанавливающим badbit/failbit флаги вместо этого.
Два вопроса...
a: Почему это - Это кажется нечетным проектным решением для языка, созданного за исключениями в нем со дня один?
b: Как лучше всего избежать этого? Я мог произвести классы контейнера, которые бросают, как я ожидал бы, но это испытывает желание изобретать велосипед. Возможно, существует библиотека BOOST, которая делает это более нормальным способом?
а. C ++ не создавался с исключениями с первого дня. «C с классами» появился в 1979 году, а исключения были добавлены в 1989 году. Между тем, библиотека streams
была написана еще в 1984 году (позже стала iostreams
в 1989 году (позже переопределена GNU) в 1991 году)), он просто не может использовать обработку исключений вначале.
Ссылка:
b. Вы можете включить исключения с помощью метода .exceptions
.
// ios::exceptions
#include <iostream>
#include <fstream>
#include <string>
int main () {
std::ifstream file;
file.exceptions ( ifstream::failbit | ifstream::badbit );
try {
file.open ("test.txt");
std::string buf;
while (std::getline(file, buf))
std::cout << "Read> " << buf << "\n";
}
catch (ifstream::failure e) {
std::cout << "Exception opening/reading file\n";
}
std::cout.flush();
file.close();
return 0;
}
Как говорит Кенни, вы можете включить исключения, если хотите. Но обычно ввод-вывод требует определенного стиля программирования при возникновении ошибки, что нелегко поддержать с помощью исключений - тестирование состояния потока после операции ввода намного проще. На самом деле я никогда не видел кода C ++, который использовал бы исключения для ввода-вывода.
Каждый раз, когда вы генерируете исключение, вы должны думать о безопасности исключений. Так что никаких исключений, никаких исключений, никакой головной боли, связанной с безопасностью исключений.
Iostreams также поддерживают исключения. Но бросать исключение необязательно. Вы можете включить исключение, установив exceptions (failbit | badbit | eofbit).
Iostreams позволяют поддерживать как исключительное поведение, так и поведение без ожиданий.
Ладно, настало время "Ответить на свой вопрос"...
Во-первых, спасибо KennyTM за историю. Как он говорит, C++ был НЕ разработан с исключениями с первого дня, поэтому неудивительно, что обработка "исключений" в iostreams была прикручена позже.
Во-вторых, как отмечает Нил Б, наличие исключений при ошибках преобразования формата ввода было бы большой проблемой. Это удивило меня, потому что я рассматривал iostreams как простой слой обертки файловой системы, и я вообще не рассматривал этот случай.
В-третьих, похоже, что BOOST действительно привносит что-то новое: Boost.IOStreams. Если я правильно понимаю, они занимаются низкоуровневым вводом/выводом и буферизацией потоков, оставляя обычную библиотеку IOStreams для работы с преобразованиями. Boost.IOStreams действительно использует исключения, как я и ожидал. Если я правильно понимаю, пример Кенни мог бы выглядеть так:
#include <ostream>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/stream.hpp>
int main () {
boost::iostreams::stream_buffer <boost::iostreams::file_source> buf("test.txt");
std::istream file(&buf);
try {
std::string buf;
while (std::getline(file, buf))
std::cout << "Read> " << buf << "\n";
}
catch (std::ios_base::failure::failure e) {
std::cout << "Exception opening/reading file\n";
}
std::cout.flush();
file.close();
return 0;
}
Я думаю, что в этой версии такие вещи, как "файл не найден" должны отбрасываться, но ошибки 'istream' будут сообщаться badbit/failbit.