Исключение со стеком вызовов (stacktrace) в C++23 #
Большая сложность при разработке на C++ в том, что у исключений нет stacktrace. Впрочем, некоторые проекты на C++ вовсе избегают использования любых исключений.
Но если вы в своих проектах используете C++23 (или выше) и хотите иметь стек вызовов для некоторых типов исключений — эта статья для вас.
Заголовочный файл <stacktrace> #
В стандарте C++23 появился заголовочный файл <stacktrace>.
По состоянию на 21 марта 2026 года поддержка <stacktrace> выглядит так:
| Компилятор | STL | Статус |
|---|---|---|
| GCC | libstdc++ | Поддерживается с версии 12.1 |
| MSVC | Microsoft STL | Поддерживается с выпуска VS 2022 17.4 |
| Clang | libc++ | Не поддерживается |
В большинстве дистрибутивов GNU/Linux используется libstdc++ и <stacktrace> будет работать, но если у вас в проекте используется libc++ — посмотрите в сторону Boost.Stacktrace.
Класс исключения с поддержкой stacktrace #
Допустим, мы назовём этот класс InternalErrorException и разместим его в пространстве имён diagnostics.
Будем добавлять стек вызовов к диагностическому сообщению исключения в таком формате:
{what}
stacktrace:
{stacktrace}Заголовочный файл InternalErrorException.h:
#pragma once
#include <stdexcept>
namespace diagnostics
{
class InternalErrorException : public std::runtime_error
{
public:
explicit InternalErrorException(const std::string& message);
};
} // namespace diagnostics
Файл реализации InternalErrorException.cpp:
#include "InternalErrorException.h"
#include <sstream>
#include <stacktrace>
namespace diagnostics
{
namespace
{
std::string appendStackTrace(const std::string& message)
{
std::ostringstream os;
os << message << "\nstacktrace:\n";
os << std::stacktrace::current(1);
return os.str();
}
} // namespace
InternalErrorException::InternalErrorException(const std::string& message)
: std::runtime_error(appendStackTrace(message))
{
}
} // namespace diagnostics
Как это выглядит #
На GNU/Linux с GCC выше 12.1 результат печати этого исключения в консоль выглядит так:
attribute not set yet
stacktrace:
0# diagnostics::InternalErrorException::InternalErrorException(std::
__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >
const&) at /src/pstigercpp/src/
libdiagnostics/exceptions/InternalErrorException.cpp:20
1# ast::AstAttribute<std::reference_wrapper<ast::BuiltinFunction const> >:
:get() const at /src/pstigercpp/src/libast/
expressions/../attributes/AstAttribute.h:27
2# ast::FunctionCallExpression::function() const at /project/src//libast/expressions/FunctionCallExpression.
cpp:25
[...]
14# Catch::RunContext::invokeActiveTestCase() at :0
15# Catch::RunContext::runCurrentTest(std::__cxx11::basic_string<char, std:
:char_traits<char>, std::allocator<char> >&, std::__cxx11::basic_string<char,
std::char_traits<char>, std::allocator<char> >&) at :0
16# Catch::RunContext::runTest(Catch::TestCaseHandle const&) at :0
17# Catch::Session::runInternal() at :0
18# Catch::Session::run() at :0
19# main at :0
20# __libc_start_call_main at ../sysdeps/nptl/libc_start_call_main.h:58
21# __libc_start_main_impl at ../csu/libc-start.c:360
22# _start at :0
23# Объяснения:
- я заменил полный путь к своему проекту на
/project/ - я заменил фреймы с номерами 3-13 на
[...], чтобы не загромождать эту статью - основной текст исключения выглядит так:
attribute not set yet - всё, идёт после
stacktrace:— это результат выводаstd::stacktraceвstd::ostreamсредствами STL (libc++)