The guard saves and disables interrupts in its constructor and restores them in its destructor:
class CriticalSection {
uint32_t primask_;
public:
CriticalSection() { primask_ = __get_PRIMASK(); __disable_irq(); }
~CriticalSection() { __set_PRIMASK(primask_); }
};You use it as { CriticalSection cs; shared++; }. It beats manual __disable_irq()/__enable_irq() pairs in three ways: the re-enable can't be forgotten or skipped by an early return, since the destructor runs on every exit; it restores the previous PRIMASK state rather than blindly enabling, so it nests correctly (an inner guard won't wrongly re-enable interrupts that an outer guard disabled); and the protected region is scoped by braces, making it visually obvious. The one rule: name the object (CriticalSection cs;), because an unnamed temporary is destroyed immediately and protects nothing.