Как улучшить сообщения об исключениях для потоков?

Эта проблема

На данный момент поддержка исключений для потоков ужасна. Когда библиотека Boost.System была принята в C ++ 11, создалось впечатление, что возможно исключения улучшатся. Все изменения были заменены std::exception на std::system_error. Хотя <system_error> сама по себе является хорошей библиотекой для разработчиков, стандартный комитет и разработчики стандартной библиотеки не предприняли никаких шагов для ее использования для улучшения сообщений об исключениях.

Чтобы понять, насколько это ужасно, вот краткое изложение того, что происходит:

  • Произошла ошибка.

  • setstate используется для установки badbit или failbit.

  • clear вызывается setstate.

  • Если включены исключения, clear выдаст ios_base::failure.

Да, это означает, что для ВСЕХ ошибок выдается одно и то же бесполезное сообщение об исключении. Это указано на уровне basic_ios, поэтому от этой проблемы страдают все производные классы. Оскорбительная цитата:

[iostate.flags] / 4 Эффекты: если ((state | (rdbuf() ? goodbit : badbit)) & exceptions()) == 0, возвращается. В противном случае функция создает объект fail класса basic_ios::failure (27.5.3.1.1), созданный с использованием значений аргументов, определенных реализацией.

Вот пример того, что дают нам «значения аргументов, определяемые реализацией»:

ios_base::clear: unspecified iostream_category error

Есть ли простое решение?

Ни Boost.Filesystem, ни Boost.Iostreams не заменяют <iostream>. Первая представляет собой библиотеку для переносимой работы с файловой системой (и, вероятно, появится в следующей версии C ++), а вторая имеет какое-то отношение к ... Источникам и приемникам. В документации указано, что она в любом случае делегирует исключения ios_base::failure. Boost.Filesystem предоставляет <boost/filesystem/fstream.hpp>, который использует path вместо const char* аргументов для open(). Он показывает пример того, как можно наследовать классы стандартной библиотеки:

  template < class charT, class traits = std::char_traits<charT> >
  class basic_ifstream : public std::basic_ifstream<charT,traits>
  {
  private: // disallow copying
    basic_ifstream(const basic_ifstream&);
    const basic_ifstream& operator=(const basic_ifstream&);

  public:
    basic_ifstream() {}

    // use two signatures, rather than one signature with default second
    // argument, to workaround VC++ 7.1 bug (ID VSWhidbey 38416)

    explicit basic_ifstream(const path& p)
      : std::basic_ifstream<charT,traits>(p.BOOST_FILESYSTEM_C_STR, std::ios_base::in) {}

    basic_ifstream(const path& p, std::ios_base::openmode mode)
      : std::basic_ifstream<charT,traits>(p.BOOST_FILESYSTEM_C_STR, mode) {}

    void open(const path& p)
      { std::basic_ifstream<charT,traits>::open(p.BOOST_FILESYSTEM_C_STR, std::ios_base::in); }

    void open(const path& p, std::ios_base::openmode mode)
      { std::basic_ifstream<charT,traits>::open(p.BOOST_FILESYSTEM_C_STR, mode); }

    virtual ~basic_ifstream() {}
  };

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

Схема наследования iostream

Я подозреваю, что необходима полная перезапись, потому что простой замены clear() будет недостаточно. Поток может завершиться ошибкой по нескольким причинам, но возникает только один тип исключения. Хотя std::system_error дает нам лучшие инструменты для выражения ошибок, это не помогает, если, опять же, нет способа определить источник ошибки.

Однако я не писатель библиотеки и не хочу брать на себя эту задачу. Есть ли другие варианты, кроме тех, которые я перечислил?


person user5378483    schedule 26.09.2015    source источник
comment
У меня нет ответа для вас, но я хотел бы сказать, что мне нравится ваш вопрос, поскольку он хорошо сформулирован и структурирован и затрагивает очень хорошую тему и проблему, вызывающую беспокойство.   -  person Francis Cugler    schedule 26.09.2015
comment
Что ж, вы могли бы начать проект с открытым исходным кодом, чтобы написать это. Но вам нужно найти руководителя проекта, если вы не хотите быть собой ... Хорошая вещь в этом заключается в том, что даже если это будет полная переписывание, результатом будет отказ от замены при условии, что новые исключения наследуются от старых один.   -  person Serge Ballesta    schedule 26.09.2015
comment
Я думаю, что между этими io-флагами и исключением есть разница в том, что вам нужно определить целый блок кода, чтобы исключения произошли и были перехвачены. В некоторых случаях исключения выполняются медленнее, но хорошо, что в C ++ вы можете выбирать, использовать их или нет. Я согласен с вами, что это необходимо улучшить, и я надеюсь, что следующий стандарт C ++ учтет это. И если нет, возможно, объясните здесь, почему эта реализация.   -  person Gerhard Stein    schedule 27.09.2015
comment
Кажется, лучший обходной путь - не использовать C ++ для ввода-вывода.   -  person Walter    schedule 01.10.2015
comment
@Walter ну, я бы сказал: возможно, лучший обходной путь - не использовать iostreams! Вы по-прежнему можете использовать cstdio, любую библиотеку или системные вызовы.   -  person M.M    schedule 05.10.2015


Ответы (1)


Boost - это проект с открытым исходным кодом, поэтому, как я вижу, есть 2 варианта:

  1. Жаловаться. Либо напишите отчет об ошибке, либо войдите в список рассылки и предложите улучшение, либо и то, и другое. Если сообщество посчитает, что вы правы, кто-то может взять его на себя.
  2. Сделайте 1, а затем сделайте что-нибудь с этим. Вы, вероятно, получите некоторую поддержку со стороны сообщества. Вы могли не быть писателем библиотеки, но, возможно, люди, стоящие за boost, тоже не были, пока они не были.

Нет волшебного способа исправить это, кто-то должен делать эту работу.

person ventsyv    schedule 05.10.2015