Подтвердить что ты не робот

Как документировать все исключения, которые может вызывать функция?

Если у вас есть общедоступная функция, которая может генерировать исключение, которое использует другие (частные или общедоступные) вспомогательные функции, которые также могут генерировать исключения, я думаю, вы должны документировать, какие исключения может публиковать публичная функция, и это включает исключения, вызванные вспомогательными функциями.

Что-то вроде этого (используя Doxygen):

/** 
 * @throw Exception ...
 * @throw ExceptionThrownByHelper ...
 * @throw ExceptionThrownByHelpersHelper ...
 */
void theFunction() 
{ 
    helperWhichMayThrowException();
}

и helperWhichMayThrowException() также вызывает другие функции, которые могут вызывать исключения.

Для этого вы можете:

  • рекурсивно выполнять все функции theFunction() вызовов и искать исключения, отложенные этой функцией. Это большая работа, и вы можете забыть о каком-либо исключении документа, когда вы добавляете исключение в помощника.
  • поймать все исключения, создаваемые помощниками в theFunction(), и преобразовать их, чтобы вы были уверены, что выбраны только те исключения, которые вы указали. Но зачем использовать исключения?
  • не волнуйтесь об исключениях, вызванных вспомогательными функциями, но затем вы не можете удалить все исключения, потому что не знаете, какие исключения могут быть выбраны публичной функцией
  • У вас есть инструмент, который (полу) автоматически перечисляет все исключения, создаваемые помощниками и т.д. Я просмотрел документацию Doxygen, но не нашел способ сделать это.

Я хотел бы использовать опцию 4, но пока не нашел хорошего решения, возможно, это возможно с Doxygen? Или, может быть, я просто хочу документировать много???

edit: Возможно, это не совсем понятно, но я ищу простой способ документировать все исключения (желательно с помощью Doxygen), которые функция может бросать без ручной проверки всех вспомогательных функций. Легкий способ включает "не документировать все исключения" или "улавливать и преобразовывать все исключения в theFunction()"

4b9b3361

Ответ 1

Я придумал следующее руководство. В основном я просто копирую документацию @throw от членов, которых я вызываю. Было бы неплохо, если бы у Doxygen был @copythrows, похожий на @copydoc, но будет работать следующее:

class A {
    public:
        /** @defgroup A_foo_throws
         *
         * @throws FooException
         */

        /** 
         * @brief Do something.
         *
         * @copydetails A_foo_throws
         */
        void foo();
};

class B {
    public:
        // This group contains all exceptions thrown by B::bar()
        // Since B::bar() calls A::foo(), we also copy the exceptions
        // thrown by A::foo().

        /** @defgroup B_bar_throws
         *
         * @copydetails A_foo_throws
         * @throws BarException
         */

        /**
         * @brief Do something else.
         *
         * @copydetails B_bar_throws
         */
        void bar();
};  

Затем в файле конфигурации Doxyfile добавьте *_throws в EXCLUDE_SYMBOLS. Это гарантирует, что эти группы не отображаются в виде модулей.

Затем B::bar() приводит к этой документации:

void B:: bar()
 Сделайте что-нибудь еще.

Исключения:
   FooException
  Исключения:
   BarException

Ответ 2

В принципе, то, что вы просите, невозможно практически в любой реальной ситуации.

Есть две части для документирования брошенных исключений.

1) Легкий бит. Задокументируйте исключения, которые были непосредственно выбраны в вашем методе. Вы можете сделать это вручную, но это довольно сложно, и если вы не сможете синхронизировать документы с кодом, документация становится вводящей в заблуждение (потенциально хуже, чем отсутствие документации вообще, так как вы можете действительно доверять документации, что вы уверены на 100% точнее). Моя надстройка AtomineerUtils позволяет сделать это намного легче, поскольку она синхронизирует комментарии кода и документа с минимальными усилиями.

2) Невозможный бит. Документируйте все исключения, которые могут "проходить" ваш метод. Это означает, что вы рекурсируете через все поддерево методов, называемых вашим методом, чтобы увидеть, что они могут выбросить. Почему невозможно? Ну, в простейших случаях вы статически привязываетесь к известным методам и можете сканировать их, чтобы увидеть, что они бросают - умеренно легко. Но большинство случаев в конечном итоге вызывают динамически связанные методы (например, виртуальные методы, отраженные или COM-интерфейсы, внешние библиотечные методы в dll, API-интерфейсы операционной системы и т.д.), Для которых вы не можете окончательно определить, что может быть выбрано (поскольку вы не знаете то, что вызывается до тех пор, пока вы фактически не запустите программу на ПК конечного пользователя - каждый компьютер отличается, а код, выполняемый на (например) WinXP и Win7, может быть совсем другим. Или представьте, что вы вызываете виртуальный метод, а затем кто-то добавляет подключаемый модуль - в вашу программу, которая переопределяет метод и генерирует новый тип исключения). Единственный способ надежно справиться с этой ситуацией - это поймать все исключения в вашем методе, а затем перебросить конкретные, которые затем могут быть задокументированы точно - если вы не можете этого сделать, тогда документация об исключениях в значительной степени ограничена "обычно брошенные и обычно ожидаемые исключения" в вашем методе, оставляя "исключительные ошибки" оставленными в основном недокументированными и просто переданными на блоки блокировки необработанных исключений более высокого уровня. (Это ужасное "исключение" undefined ", которое часто приводит к необходимости использования catch (...) - академически это" зло ", но если вы хотите, чтобы ваша программа была пуленепробиваемой, вам иногда приходится используйте catch-alls, чтобы убедиться, что непредвиденные ситуации не убивают ваше приложение).