C++26 adds a <debugging> header with std::breakpoint and std::is_debugger_present
A blog post by Sandor Dargo explains the new
The new header provides three functions. All three are noexcept and freestanding, and none are constexpr, because debugging is a runtime concern.
std::breakpoint() is an unconditional breakpoint. With a debugger attached, execution halts and control passes to the debugger; on x86 this typically compiles to a single int3 instruction. With no debugger present, the behaviour is implementation-defined. On most platforms the process receives a signal (such as SIGTRAP) and terminates unless the signal is caught.
std::is_debugger_present() returns true if the program is currently being traced by a debugger. The check runs on every call and the result is not cached, because a debugger can attach or detach at any time. The mechanism differs by platform: on Windows an implementation might call ::IsDebuggerPresent(), while on Linux GCC's libstdc++ reads /proc/self/status and checks the TracerPid field. The standard mandates no particular mechanism. The semantics are implementation-defined, with the intended behaviour described in non-normative notes.
What makes this function unusual is that it is replaceable, in the same sense as operator new and operator delete, so users can define their own version. P2810R4 introduced this to solve the freestanding problem. On bare-metal platforms there may be no OS-level way to detect a debugger. Without replaceability, the function would either have to be excluded from freestanding (forcing #ifdef guards everywhere) or return a useless default. Replaceability lets a developer wire it to whatever the platform provides.
std::breakpoint_if_debugging() is the convenience function the author expects most users to reach for. When a debugger is attached, it hits a breakpoint; when none is, nothing happens. It is the pattern Catch2, Boost.Test and other frameworks implement by hand.
The post also notes that having is_debugger_present() as a separate function allows more than conditional breakpoints. You might use it to produce extra diagnostic output while debugging, disable timeouts that would fire during a stepping session, switch to a more debugger-friendly allocator, or skip optimizations that make debugging harder. The separation is deliberate: breakpoint() and is_debugger_present() are orthogonal building blocks, and breakpoint_if_debugging() is the convenience composition of the two.
The author's conclusion is that
Key facts
- C++26 adds a
header with three functions: std::breakpoint(), std::is_debugger_present() and std::breakpoint_if_debugging(), specified in P2546R5 and its companion P2810R4. - All three functions are noexcept and freestanding; none are constexpr, because debugging is a runtime concern.
- std::breakpoint() halts in an attached debugger (typically a single int3 on x86); with no debugger, behaviour is implementation-defined, and on most platforms a signal such as SIGTRAP terminates the process unless caught.
- std::is_debugger_present() is replaceable like operator new and operator delete, so bare-metal platforms with no OS-level debugger detection can supply their own version.
- The header replaces per-project macros such as Boost.Test debugger_break(), Catch2 CATCH_BREAK_INTO_DEBUGGER, Dear ImGui IM_DEBUG_BREAK() and Unreal UE_DEBUG_BREAK.
Why it matters
Breaking into the debugger from code is something nearly every large C++ codebase needs, and until C++26 it had no standard spelling. Boost.Test, Catch2, Dear ImGui and Unreal each carry their own macro, built on platform knowledge that tooling implementers already have. The new header moves that knowledge into the standard library in the form of three small functions. The author's view is that this is overdue and that simple additions are sometimes the most useful ones.
Who it affects
C++ developers who write test frameworks, assertion macros, logging or diagnostics code, and anyone who has hand-rolled a breakpoint snippet. Embedded and bare-metal developers are affected by the replaceability of std::is_debugger_present(), which was added specifically because such platforms may have no OS-level way to detect a debugger. Maintainers of projects like Boost.Test, Catch2, Dear ImGui and Unreal have their own macros that the standard functions now cover.
How to use it
According to the post, most users will reach for std::breakpoint_if_debugging(), which breaks when a debugger is attached and does nothing otherwise, replacing the hand-written pattern. Use std::breakpoint() when you want an unconditional stop, and std::is_debugger_present() when you want to change behaviour under a debugger: extra diagnostic output, disabled timeouts during stepping, a more debugger-friendly allocator, or skipped optimizations that hinder debugging. On platforms without a built-in detection mechanism, you can define your own std::is_debugger_present(), the way you can replace operator new. The post names no compiler or standard library version as already shipping the header, apart from the GCC libstdc++ mechanism description.
How solid is it
The header is a standardized C++26 feature, backed by named proposals (P2546R5 and P2810R4), and the post's technical descriptions are specific: the int3 instruction on x86, ::IsDebuggerPresent() on Windows, and the TracerPid field in /proc/self/status on Linux with GCC's libstdc++. The post is one author's explainer and gives no benchmarks or performance figures. The conclusion that the feature is overdue is the author's opinion.
Risks and caveats
Behaviour is left to the implementation in several places. Calling std::breakpoint() with no debugger attached is implementation-defined, and on most platforms the process gets a signal such as SIGTRAP and terminates unless the signal is caught. The semantics of std::is_debugger_present() are also implementation-defined, with intended behaviour in non-normative notes, and the standard mandates no detection mechanism. The result is not cached, since a debugger can attach or detach at any time, so it can change between calls. The post does not state when C++26 is finalized or published as an ISO standard.
“Sometimes the most useful standard library additions are the simplest ones.”
— Sandor Dargo, C++26: The New Debugging Header