在Linux环境下用C++做开发,错误处理是个绕不开的话题。不同的场景、不同的代码风格,选择也不一样。下面梳理了几种主流的方法,看看它们各自在什么场合更顺手。

返回错误码
这是最经典、也最直接的方式。函数通过返回值来传递执行结果:通常0代表成功,非零就表示出了某种问题。C语言时代大量用这种方法,C++里也完全兼容。代码写起来很直观:
int result = someFunction();
if (result != 0) {
// 处理错误
}
好处是简单、零开销,特别适合对性能敏感或者不允许抛异常的场景。缺点嘛,得靠开发者自觉检查返回值,忽略了就是隐患。
异常处理
C++自带的 try-catch-throw 机制,属于面向对象时代的标准做法。把可能出问题的代码放进 try 块,遇到错误直接 throw 一个异常对象,然后在 catch 里统一处理。资源管理上配合 RAII,能让代码更干净:
try {
someFunctionThatMightThrowException();
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
} catch (...) {
// 处理未知类型的异常
}
异常机制最大的优势是能强制错误处理——不 catch 程序就会终止,避免漏检。不过注意,在嵌入式或实时系统里,异常可能带来性能和栈展开的不确定性,得掂量着用。
errno 全局错误码
继承自C语言的全局变量 errno,配合 strerror 能获取可读的错误信息。虽然C++里也能用,但现代C++社区更倾向于用异常或返回码,因为 errno 是线程局部存储,而且容易不小心被覆盖:
#include
#include
int result = someFunction();
if (result == -1) {
std::cerr << "Error: " << std::strerror(errno) << std::endl;
}
如果你需要跟C库函数打交道,或者维护老代码,errno 还是得懂。但在新项目里,尽量找更现代的替代方案。
assert 断言
assert 是调试阶段的利器。它检查一个条件,如果为假就直接终止程序,并告诉你哪里出了问题。适合用来捕捉“不可能发生”的逻辑错误:
#include
int result = someFunction();
assert(result != -1 && "someFunction failed");
注意,assert 只在调试模式下生效,发布版里不会执行。所以别用它来处理运行时错误,比如用户输入错误或网络超时——这些应该用异常或返回码。
自定义错误处理类
当内置机制不够灵活时,可以自己封装一个错误处理类。把错误码、错误信息、甚至修复建议都包进去,让处理逻辑更统一:
class ErrorHandler {
public:
ErrorHandler(int code, const std::string& message) : code(code), message(message) {}
void handleError() const {
std::cerr << "Error " << code << ": " << message << std::endl;
}
private:
int code;
std::string message;
};
int result = someFunction();
if (result != 0) {
ErrorHandler(err, "someFunction failed").handleError();
}
这种做法特别适合大型项目,方便统一日志、记录上下文、甚至做自动恢复。当然,团队需要约定好接口规范,否则容易变成各自为战。
使用第三方库
社区也提供了一些成熟的错误处理组件,比如Boost库里的 boost::system::error_code 和 error_condition。它们把错误码和信息封装得更完善,还支持自定义分类:
#include
boost::system::error_code ec;
someFunction(ec);
if (ec) {
std::cerr << "Error: " << ec.message() << std::endl;
}
用第三方库的好处是经过大量实践检验,缺点就是依赖引入了。如果项目已经用了Boost,顺手用它做错误处理是很自然的选择。
最后说句实在的,没有一种方法能包打天下。一般情况下,可预见的错误(比如打开文件失败)用返回码或异常处理最稳妥;而不可预见的逻辑谬误(比如不该为空的指针)交给 assert 在调试阶段发现就好。关键是根据项目规模、性能需求和团队习惯,找到最适合自己的组合。