簡體   English   中英

使用 `std::error_code` 的最佳實踐

[英]Best practices for using `std::error_code`

我目前正在構建一個嵌入式系統並使用現代 C++ 編譯器。 雖然我在技術上可以在給定的資源(ARM7,超過 10M RAM)中進行異常處理,但我認為異常不是處理此類事情的正確工具,並且使用異常需要 RTTI,這反過來會導致代碼膨脹。

無論如何,為了保持 C++ 風格,我想使用std::error_code (或類似的更多數據),因為我確實喜歡這個概念。

但是,對於如何實際使用它們似乎沒有任何共識。 我已經看到至少四種不同的方式在 function 調用之間傳遞它們,其中兩種具有多種語義。

  1. 通過指針作為參數傳遞

    void somefunction(Args..., std::error_code* error);

    這是我不經常看到的方式,也是我最不喜歡的方式。 它使返回類型完全可用,並且(通常但不總是)傳遞nullptr導致正常的拋出行為。

  2. 通過引用作為參數傳遞

    void somefunction(Args..., std::error_code& error);

    這是我更喜歡的一個。 它使returnvalue完全可用,並清楚地表明error_code不是可選的。

  3. 按值返回

    std::error_code somefunction(Ret& out <= if used, Args...);

    我經常看到這個,但不是很喜歡它,因為它會耗盡你的返回值,而且我通常不喜歡“輸出參數”,除非沒有辦法繞過它們。

  4. 返回一個std::variant<Ret, std::error_code>

     std::variant<Ret, std::error_code> somefunction(Args...);

    這允許返回值,但使訪問值和錯誤更加困難。 此外,它使調用 function 的代碼更加冗長。

語義

如果傳遞了error_code ,我已經看到了具有不同語義的方式1和2。

  • 啟動時清除並設置錯誤
  • 僅設置錯誤
  • 如果error_code為“set”,則在開始時立即返回

如果您想減少調用代碼中的錯誤檢查,最后一種方法非常好。 因為您可以只將一個error_code傳遞給多個函數,而無需在兩者之間進行檢查,並且第一個錯誤之后的所有內容都不會執行,類似於異常的執行方式。

我個人確實更喜歡檢查和返回的方式2,但是我可能有偏見。

有一些推薦/普遍接受的方法嗎?

好的,這不是完整的答案,實際上也不是完美的主題,因為我不知道執行此操作的標准方法。 但是我曾經看到一個漂亮的小技巧,可以讓錯誤代碼更難被誤用。 考慮以下代碼:

struct MyEC {
    MyEC() {}
    MyEC(MyEC && other) : parent(&other) {
        // Maybe log and or abort if other is not checked
        other.checked = false;
    }
    // Delete other constructors and assignment operators

    ~MyEC() { 
        if(!checked && parent == nullptr) {
            // log and or abort
        }
     }

    [[nodiscard]] std::error_code check() {
        checked = true;
        return ec;
     }
 
     void set(std::error_code err) {
         if(parent == nullptr)  ec = err;
         else parent->set(err);
     }
private:
    MyEC* parent = nullptr;
    checked = true;
    std::error_code ec {};
};

int foo(MyEC&& err) {
    err.set(/* some error */);
    return 5;
}

int foo1(MyEC&&) {
    return 4;
}

void bar() {
    MyEC err;
    foo(std::move(err));
    // err has the error code and if its not checked, we will know
 

    foo1(std::move(err));
    // even though no error occurs, we will abort if err is not checked.
}

當錯誤代碼未設置但也未檢查時,它甚至會中止,這非常好。 移動后有很多用處,有點奇怪,不過這里沒問題。

暫無
暫無

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

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