在C++20中,std::source_location提供了获取当前代码位置的能力,包括文件名、行号、列号和函数名。把它运用到异常处理流程里,我们能够在异常被抛出的瞬间自动记录崩溃点,而不必手工填写位置信息。
为什么需要自动记录崩溃点
很多项目依赖日志来排查问题。如果异常只携带一句错误信息,出问题时我们往往要全局搜索字符串才能定位代码。使用std::source_location后,异常对象自身就带有抛出位置,排查时直接看日志即可。
设计带位置的异常类
我们可以定义一个轻量异常类,在构造函数中接收std::source_location的默认参数,从而自动捕获调用处信息。
#include <source_location>
#include <stdexcept>
#include <string>
class LocatedException : public std::runtime_error {
public:
LocatedException(const std::string& msg,
const std::source_location& loc = std::source_location::current())
: std::runtime_error(make_msg(msg, loc)), loc_(loc) {}
const std::source_location& location() const { return loc_; }
private:
std::source_location loc_;
static std::string make_msg(const std::string& msg,
const std::source_location& loc) {
return msg + " @ " + loc.file_name() + ":" +
std::to_string(loc.line()) + " " + loc.function_name();
}
};
在业务中抛出并捕获
下面示例展示在可能出错的函数中直接抛出带位置的异常,并在外层统一打印。
#include <iostream>
void process(int v) {
if (v < 0) {
throw LocatedException("invalid value");
}
}
int main() {
try {
process(-1);
} catch (const LocatedException& e) {
std::cerr << "catch: " << e.what() << std::endl;
} catch (const std::exception& e) {
std::cerr << "std ex: " << e.what() << std::endl;
}
return 0;
}
注意事项
- std::source_location::current()是编译期求值,默认参数会在调用点展开,因此位置准确。
- 若异常经过多层转发,应在首次抛出时捕获位置,避免后续包装丢失原始点。
- 不支持C++20以下标准,老项目可用宏__FILE__和__LINE__模拟类似效果。
小结
把std::source_location融入异常体系,可以用很小成本让每次崩溃都自带坐标。配合日志系统,能显著减少线上问题定位时间。
std::source_locationC++异常处理崩溃点记录修改时间:2026-07-29 13:27:25