ワンクリックで
cpp-safety
Use when writing or reviewing any C++ class that owns resources, has a destructor, or acquires in a constructor.
メニュー
Use when writing or reviewing any C++ class that owns resources, has a destructor, or acquires in a constructor.
Use when adding new classes, refactoring code, or reviewing PRs for Particle-Viewer.
Use when a task needs design exploration before any implementation begins. Required for any task with unclear approach, significant architecture impact, or multiple valid solutions.
Use when building, adding dependencies, configuring CMake options, troubleshooting build failures, or managing Flatpak packaging for Particle-Viewer.
Use when writing or reviewing C++ code, running pre-commit checks, or addressing formatting, naming, or static analysis violations.
Use when writing tests for any interface, abstract base class, or type with multiple implementations.
Use when implementing C++ code for Particle-Viewer, handling GL resources, working with SDL3, or applying DRY/deprecation/docs-commit patterns.
| name | cpp-safety |
| license | MIT |
| description | Use when writing or reviewing any C++ class that owns resources, has a destructor, or acquires in a constructor. |
DESTRUCTORS NEVER THROW -- EVERY RESOURCE IS OWNED BY A SCOPE-BOUND GUARD
YOU MUST wrap every destructor body in try/catch and ensure every resource acquisition is handed to an owning guard before the next acquisition begins. No exceptions.
Violating the letter of this rule is violating the spirit of this rule.
Announce at start: "I am using the cpp-safety skill to review [class]."
[+] No owned resources -> skip this skill [-] Any owned resource -> apply the rules below
Throwing from a destructor during stack unwinding calls std::terminate -- no other destructors run. Wrap every destructor body in try/catch; never rethrow.
If the constructor acquires resource A then throws while acquiring resource B, A leaks -- the destructor is never called on a partially-constructed object. Each acquisition must be handed to its own scope-bound guard before the next acquisition begins.
When acquisition happens in a factory method (not a constructor) using raw pointers: if unique_ptr cannot be used (e.g., the pointer is a member reset by a helper method), wrap the second new in try-catch -- delete and null the first pointer before rethrowing:
void createResources() {
executor_ = new Executor();
try {
cache_ = new Cache(*executor_);
} catch (...) {
delete executor_;
executor_ = nullptr;
throw;
}
}
See the cpp-patterns skill for ownership patterns and OpenGL-specific examples.
| Excuse | Reality |
|---|---|
| "The cleanup is simple, it won't throw" | Wrap now -- that property must hold for all future edits. |
"std::terminate is acceptable here" | Not during stack unwinding -- it prevents all remaining destructors from running. |
| "The second allocation almost never fails" | "Almost never" is not a safety guarantee. Wrap in a scope-bound guard. |
| "Owning guards add boilerplate" | The boilerplate is the guarantee. Inline cleanup is a future leak. |
| "The partial construction case never happens in practice" | "Never in practice" is not a structural guarantee. Scope-bound guards prevent the case unconditionally -- no statistical argument required. |
new or open call.delete instead of a scope-bound guard -- STOP. Replace with unique_ptr or a custom RAII wrapper.cpp-patterns -- parent skill; OpenGL smell catalog and DRY patternsoop-principles -- sibling; resource-owning types also need the Is-A / Has-A gatesystematic-debugging -- sibling; use when a crash points to destructor failure