簡體   English   中英

如何記錄函數可能拋出的所有異常?

[英]How to document all exceptions a function might throw?

如果你有一個公共函數可能拋出一個異常,它使用其他(私有或公共)輔助函數也可以拋出異常,我認為你應該記錄公共函數可以拋出的異常,這包括輔助函數拋出的異常

像這樣(使用Doxygen):

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

helperWhichMayThrowException()也調用可能拋出異常的其他函數。

為此,您可以:

  1. 遞歸地遵循函數theFunction()函數theFunction()調用的所有函數,並查找該函數所引發的異常。 這是很多工作,當您向助手添加異常時,您可能忘記在某處記錄異常。
  2. 捕獲theFunction()助手拋出的所有異常並轉換它們,以確保只拋出指定的異常。 但那么為什么要使用例外?
  3. 不要擔心輔助函數拋出的異常,但是你不能對所有異常進行單元測試,因為你不知道公共函數可以拋出哪些異常
  4. 有一些工具(半)自動列出助手拋出的所有異常等。我查看了Doxygen的文檔,但沒有找到辦法做到這一點。

我想使用選項4,但我還沒有找到一個好的解決方案,也許它可以用Doxygen嗎? 或許我只是想要記錄多少???

編輯:也許它不是很清楚,但我正在尋找一種簡單的方法來記錄所有異常(最好使用Doxygen)函數可能拋出而無需手動檢查所有輔助函數。 一種簡單的方法包括'不記錄所有異常'或'捕獲並轉換theFunction()的所有異常

從根本上說,在幾乎每一個現實世界的情況下,你所要求的都是不可能的。

記錄拋出異常有兩個部分。

1)簡單的一點。 記錄方法中直接引發的異常。 您可以手動執行此操作,但這非常費力,如果您未能通過代碼保持文檔同步,則文檔會產生誤導(可能比完全沒有文檔更糟糕,因為您只能真正信任您確定的文檔是100%准確)。 我的AtomineerUtils加載項使這更容易實現,因為它可以使代碼和文檔注釋保持同步,而且工作量最小。

2)不可能的一點。 記錄可能“通過”您的方法的所有異常。 這意味着通過您的方法調用的整個方法子樹進行遞歸,以查看它們可能拋出的內容。 為什么不可能? 好吧,在最簡單的情況下,您將靜態綁定到已知方法,因此可以掃描它們以查看它們拋出的內容 - 適度容易。 但是大多數情況最終調用動態綁定方法(例如虛擬方法,反射或COM接口,dll中的外部庫方法,操作系統API等),你無法明確地解決可能拋出的問題(因為你不會知道)直到你真正在最終用戶的PC上運行程序才會被調用 - 每台PC都不同,並且在(例如)WinXP和Win7上執行的代碼可能完全不同。或者想象你調用虛擬方法然后有人添加插件-in到您的程序,它會覆蓋該方法並拋出一種新類型的異常)。 可靠處理這種情況的唯一方法是捕獲方法中的所有異常,然后重新拋出可以精確記錄的特定異常 - 如果你不能這樣做,那么異常的記錄幾乎限於“通常拋出並且通常預期的異常“在你的方法中,留下”異常錯誤“基本上沒有記錄,只是簡單地傳遞給更高級別的未處理異常捕獲塊。 (正是這種可怕的“未定義”異常行為經常導致使用catch(...)的必要性 - 在學術上它是“邪惡的”,但如果你想讓你的程序成為防彈,你有時必須使用catch - 以確保意外情況不會刺殺您的應用程序)。

我提出了以下手動解決方案。 基本上我只是從我打電話的成員那里復制@throw文檔。 如果Doxygen有一個類似於@copydoc@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配置文件中添加*_throwsEXCLUDE_SYMBOLS 這可以確保這些組不會顯示為模塊。

然后B::bar()導致此文檔:

void B :: bar()
做點別的。

例外:
FooException
例外:
BarException

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM