1. C++错误处理的基本范式
在C++工程实践中,错误处理机制的选择直接影响着代码的健壮性和可维护性。经过多年项目实践,我认为C++开发者主要面临三种基本错误处理范式:
1.1 返回错误码(Error Code)
这是最传统的错误处理方式,源自C语言实践。函数通过返回值或输出参数传递错误状态:
cpp复制int connectToDatabase(DatabaseHandle* outHandle) {
if (networkUnavailable) {
return ERR_NETWORK_FAILURE;
}
// ...
return SUCCESS;
}
工程实践要点:
- 使用枚举而非魔数定义错误码
- 错误码范围应分层设计(系统级/模块级/子模块级)
- 提供错误码转字符串的辅助函数
- 全局错误码变量需要线程安全保护
我在金融交易系统项目中曾采用分层错误码设计:
cpp复制enum class TradingError {
// 0-99: 核心引擎错误
ENGINE_INIT_FAILED = 1,
ENGINE_QUEUE_FULL = 2,
// 100-199: 风控模块错误
RISK_LIMIT_EXCEEDED = 101,
RISK_CHECK_TIMEOUT = 102
};
1.2 异常处理(Exception Handling)
现代C++推荐的错误处理机制,通过throw抛出、catch捕获异常:
cpp复制class DatabaseConnectionError : public std::runtime_error {
public:
DatabaseConnectionError(const std::string& msg)
: std::runtime_error(msg) {}
};
void connect() {
if (authFailed) {
throw DatabaseConnectionError("Invalid credentials");
}
}
关键优势:
- 错误处理与正常逻辑分离
- 自动调用栈展开和资源释放(通过RAII)
- 类型安全的错误信息传递
1.3 混合模式(Hybrid Approach)
在实际工程中,我们常需要混合使用异常和错误码。我的经验法则是:
- 接口边界使用错误码(兼容C或其他语言)
- 模块内部使用异常
- 性能关键路径使用错误码
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 错误码的工程化实现
2.1 错误码系统设计
一个完整的错误码系统需要考虑以下要素:
mermaid复制classDiagram
class ErrorCode {
+int code
+string domain
+string message
+string sourceLocation
+DateTime timestamp
+operator bool()
+ToString() string
}
实现建议:
- 使用组合而非继承设计错误类型
- 支持错误链(Error Chaining)追踪根源
- 内置调试信息(如抛出位置、线程ID)
- 提供日志集成接口
2.2 典型实现方案
这是我常用的错误码基类实现:
cpp复制class Error {
public:
Error(int code, std::string domain, std::string msg = "")
: m_code(code), m_domain(std::move(domain)), m_msg(std::move(msg)) {
m_stackTrace = captureStackTrace();
m_timestamp = std::chrono::system_clock::now();
}
virtual ~Error() = default;
operator bool() const { return m_code != 0; }
std::string ToString() const {
return fmt::format("[{}] {}: {} (thread:{})",
m_domain, m_code, m_msg, getThreadId());
}
protected:
std::string captur
