A Comprehensive Overview of Exception and Error Handling Across Languages and Platforms
This article surveys various error and exception handling mechanisms in C, C++, Java, Go, Rust and other languages, comparing global error codes, return values, error stacks, and OS-level support, and evaluates their advantages and drawbacks for modern software development.
The article begins by distinguishing between errors (unrecoverable, low‑level failures) and exceptions (recoverable, program‑level issues) and explains why systematic error handling is essential for reliable software.
Global Error Codes
Traditional C‑style error handling relies on a global errno variable. An example shows how fopen sets errno to ENOENT when a file cannot be opened:
#include <stdio.h>
#include <errno.h>
int main() {
FILE *file = fopen("nonexistent_file.txt", "r");
if (file == NULL) {
perror("Error opening file");
printf("Error code: %d
", errno);
} else {
fclose(file);
}
return 0;
}In multithreaded environments, errno is thread‑local, avoiding conflicts.
C++ Error Handling
C++11 introduced std::error_code and std::error_category to represent platform‑specific error conditions without global state. A custom error category for a fictional WxPay library is illustrated:
enum class WxPayErrorCode { kInvalidOpenTestFile = 0x1375212, kInvalidEmptyFile = 0x1375213 };
class WxPayErrorCategory : public std::error_category {
public:
static const WxPayErrorCategory& Instance() {
static thread_local WxPayErrorCategory instance;
return instance;
}
const char* name() const noexcept override { return "WxPayErrorCategory"; }
std::string message(int ev) const override {
switch (static_cast<WxPayErrorCode>(ev)) {
case WxPayErrorCode::kInvalidOpenTestFile: return "Cannot open test file!";
case WxPayErrorCode::kInvalidEmptyFile: return "Empty file!";
default: return "Unknown";
}
}
};
std::error_code make_error_code(WxPayErrorCode ec) {
return {static_cast<int>(ec), WxPayErrorCategory::Instance()};
}Using std::error_code allows functions to return rich error information without exceptions.
OpenSSL Error Stack
OpenSSL maintains an error stack that can be queried with ERR_get_error, ERR_peek_error, and ERR_error_string_n. A short example demonstrates pushing and printing errors:
#include <openssl/err.h>
void inner_foo() { ERR_put_error(ERR_LIB_EVP, 0, ERR_R_PEM_LIB, __FILE__, __LINE__); }
void foo() { inner_foo(); if (ERR_peek_error()) { ERR_put_error(ERR_LIB_EVP, 0, ERR_R_SYS_LIB, __FILE__, __LINE__); } }
int main() { BIO *bio = BIO_new_fp(stdout, BIO_NOCLOSE); foo(); unsigned long err = ERR_peek_error(); if (err) ERR_print_errors(bio); }Visual Basic Error Handling
VB uses the global Err object and On Error statements (e.g., On Error GoTo ErrorHandler) to capture runtime errors, optionally displaying a dialog.
Return‑Value‑Based Error Handling
Many libraries (e.g., libcurl) return an error enum such as CURLcode. The article shows a C example that checks errno after fopen and prints the error message.
Modern Language Approaches
Go prefers returning (value, error) pairs and uses defer for cleanup:
f, err := os.Open("filename.txt")
if err != nil { log.Fatal(err) }
defer func() { if err := f.Close(); err != nil { log.Fatal(err) } }()Rust uses Result<T, E> with the ? operator for concise propagation:
fn read_file(path: &str) -> Result<String, std::io::Error> {
let mut file = File::open(path)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
Ok(contents)
}C++23 introduces std::expected<T, E>, offering a value‑or‑error return without exceptions.
Boost.Outcome
Boost.Outcome provides a result<T> type with macro BOOST_OUTCOME_TRY to chain operations while handling errors.
Operating‑System Support
Windows implements Structured Exception Handling (SEH) and Vectored Exception Handling (VEH). SEH uses unwind tables ( UNWIND_INFO) for efficient stack unwinding, while VEH allows global interception of all exceptions via AddVectoredExceptionHandler and AddVectoredContinueHandler.
Conclusion
The article concludes by summarizing the trade‑offs of each approach and suggests that the choice of error‑handling strategy should align with project requirements, performance constraints, and the need for rich diagnostic information.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
