C++23 Stacktrace and Source Location: Debugging Like a Pro
Master C++23's std::stacktrace and std::source_location for production debugging.
20+ years shipping performance-critical C and C++ systems. Lessons pulled from things that broke in production.
- ✓Basic knowledge of C++ (functions, classes, exceptions)
- ✓Familiarity with C++17/20 features (e.g., structured bindings, if constexpr)
- ✓A compiler that supports C++23 (GCC 12+, Clang 14+, MSVC 2022 17.5+)
- std::stacktrace captures the current call stack as a sequence of stacktrace_entry objects.
- std::source_location provides file, line, column, and function name at compile time.
- Both are part of C++23 and require #include
and #include . - Use stacktrace for runtime debugging; use source_location for logging and assertions.
- They are zero-overhead when not used, but capturing a stacktrace has runtime cost.
Imagine you're a detective investigating a crime. std::stacktrace is like a list of all the places the suspect visited before the crime. std::source_location is like a GPS tag that tells you exactly where you are at any moment. Together, they help you trace the path of your program's execution and pinpoint where things went wrong.
Debugging complex C++ applications can be like finding a needle in a haystack. When a crash occurs deep in a library call, you often have no idea how you got there. C++23 introduces two powerful tools: std::stacktrace and std::source_location. These features bring stack trace and source location capabilities directly into the standard library, making debugging and logging more efficient and portable.
In this tutorial, you'll learn how to capture and analyze stack traces at runtime, and how to embed source location information into your logs and assertions. We'll cover practical examples, common pitfalls, and production-ready patterns. By the end, you'll be able to add robust debugging capabilities to your C++ applications with minimal overhead.
Whether you're maintaining a legacy codebase or building a new system, these tools will save you hours of debugging time. Let's dive in!
What is std::source_location?
std::source_location is a class that represents source location information (file name, line number, column number, and function name). It is obtained via the static method current(), which returns a source_location object populated with the call site's information. This is evaluated at compile time, so there is no runtime overhead when not used.
Example:
What is std::stacktrace?
std::stacktrace is a container of std::stacktrace_entry objects, each representing a frame in the call stack. You can capture the current stack trace with std::stacktrace::current(). The stacktrace can be printed or iterated. It is similar to boost::stacktrace but standard.
Example:
Using source_location in Logging Macros
One of the most practical uses of std::source_location is in logging macros. Instead of manually writing __FILE__ and __LINE__, you can define a macro that automatically passes the source location. This reduces boilerplate and ensures consistency.
Example:
Capturing Stack Traces in Exception Handlers
When an exception is thrown, the stack is unwound. To capture the stack at the throw point, you need to capture it before the exception is caught. One common pattern is to capture the stack trace in the catch block, but that gives the catch site's stack, not the throw site's. To capture the throw site, you can use a custom exception class that stores a stack trace.
Example:
Comparing Stacktrace Entries
std::stacktrace_entry provides methods to get the source file, line number, and function name. You can compare entries for equality. This is useful for deduplication or filtering.
Example:
Performance Considerations and Best Practices
Capturing a stack trace involves walking the stack and resolving symbols, which can be slow (microseconds to milliseconds). In production, you should: - Capture stack traces only on error paths. - Limit the depth using std::stacktrace::current(max_depth). - Use conditional compilation (e.g., #ifdef DEBUG) to disable stack tracing in release builds. - For source_location, there is no runtime cost when not used, but passing it by value copies the object (though it's small).
Example of conditional stack tracing:
The Mysterious Crash in the Payment Gateway
- Always capture stack traces in exception handlers for production debugging.
- Use std::source_location to automatically log file and line numbers.
- Don't assume the location of an error; let the tools tell you.
- Test your logging infrastructure with actual stack traces in staging.
- Consider performance impact: capturing stack traces is expensive; do it only when needed.
#include <source_location>auto loc = std::source_location::current();loc.function_name();| File | Command / Code | Purpose |
|---|---|---|
| source_location_demo.cpp | void log(const std::string& msg, const std::source_location& loc = std::source_l... | What is std |
| stacktrace_demo.cpp | void func3() { | What is std |
| logging_macro.cpp | void log(const std::string& msg, const std::source_location& loc) { | Using source_location in Logging Macros |
| exception_stacktrace.cpp | class traced_exception : public std::runtime_error { | Capturing Stack Traces in Exception Handlers |
| compare_entries.cpp | int main() { | Comparing Stacktrace Entries |
| conditional_stacktrace.cpp | void on_error() { | Performance Considerations and Best Practices |
Key takeaways
Common mistakes to avoid
3 patternsCapturing stack trace in catch block instead of throw point
Using std::source_location::current() outside of a default argument
Assuming stack traces are always available in release builds
Interview Questions on This Topic
What is std::source_location and how do you use it in logging?
Frequently Asked Questions
20+ years shipping performance-critical C and C++ systems. Lessons pulled from things that broke in production.
That's C++ Advanced. Mark it forged?
3 min read · try the examples if you haven't