effective-cpp
Use this skill when writing, reviewing, refactoring, or debugging C++ code — especially when the task involves class design, resource management (RAII, smart pointers, new/delete), inheritance hierarchies (virtual destructors, NVI, slicing), move semantics (std::move, std::forward, noexcept), templates (SFINAE, CRTP, type traits), exception safety, concurrency (std::atomic vs volatile, std::thread, std::async), or any C++ best practices question. Provides prioritized rules and anti-pattern detection from Scott Meyers' Effective C++, More Effective C++, and Effective Modern C++. Trigger this skill whenever user mentions C++ classes, constructors/destructors, copy/move operations, Rule of Five/Zero, const correctness, smart pointer ownership, polymorphism, or asks for C++ code review. Do NOT trigger for pure C (C89/C99), build tools (CMake/Make), test frameworks (GTest), or other languages.
git clone https://github.com/catiicode/claude-code-awesome-skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/catiicode/claude-code-awesome-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/effective-cpp" ~/.claude/skills/catiicode-claude-code-awesome-skills-effective-cpp && rm -rf "$T"
effective-cpp/SKILL.mdEffective C++ Development Guide
Best practices from Scott Meyers' three books, organized by priority for practical C++ development.
Sources: [EC] Effective C++ (55 Items) | [MEC] More Effective C++ (35 Items) | [EMC] Effective Modern C++ (42 Items)
Priority: IRON RULE (UB/crash/leak) > STRONG (correctness/maintainability) > GOOD (quality improvement)
C++ Baseline: C++11
Deep-dive references — read when working on a specific topic:
- references/iron-rules.md — Full code examples for all iron rules
- references/class-design.md — Class design, constructors/destructors, interfaces
- references/resource-management.md — RAII, smart pointers, Pimpl
- references/inheritance-templates.md — Inheritance, NVI, templates, traits
- references/move-semantics-lambdas.md — Move semantics, forwarding, lambdas
- references/concurrency.md — Threads, async, atomic, volatile
- references/performance.md — RVO, inlining, lazy/eager eval, compilation
- references/exceptions-interop.md — Exception safety, C interop, type deduction
Iron Rules — Violating These Causes UB, Crashes, or Leaks
| # | Rule | Key Point |
|---|---|---|
| 1 | RAII [EC-13, MEC-9, MEC-10] | Every resource owned by an object whose destructor releases it. No manual cleanup. Smart pointer members in constructors prevent partial-construction leaks. |
| 2 | Match new/delete forms [EC-16] | →, →. Mismatch = UB. Prefer containers over raw arrays. |
| 3 | Virtual destructor for polymorphic bases [EC-7] | Deleting derived via base pointer with non-virtual dtor = UB. Has virtual functions → needs virtual dtor. |
| 4 | No exceptions from destructors [EC-8, MEC-11] | Second exception during stack unwinding → . Wrap throws in try/catch. Provide separate close() for error handling. |
| 5 | No virtual calls in ctors/dtors [EC-9] | During base construction, dynamic type IS the base. Virtual calls resolve to base version, never derived. Pass info via ctor args. |
| 6 | No redefining non-virtual functions or default params [EC-36, EC-37] | Both are statically bound. Redefining creates confusing behavior depending on pointer type. Use NVI for defaults. |
| 7 | No polymorphic arrays [MEC-3] | ≠ breaks pointer arithmetic. Use . |
| 8 | Smart pointer ownership [EMC-18–21] | (default) / (truly shared) / (observer). Never two from same raw pointer. Use /. Store new-ed objects in smart pointers immediately [EC-17]. |
| 9 | Correct copying [EC-11, EC-12, EMC-17] | Self-assignment safety (copy-and-swap). Copy ALL parts (members + base). Rule of Five: declare any special member → declare all five. |
| 10 | std::move/forward correctness [EMC-23, EMC-25] | = unconditional rvalue cast. = conditional (universal refs). Apply on LAST use only. Never const (silently copies). Never return values (inhibits RVO). |
| 11 | atomic ≠ volatile [EMC-40] | = thread safety. = no optimization (hardware I/O). provides ZERO thread safety in C++. |
| 12 | Exception safety basics [EC-29, MEC-13] | Catch by reference (never by value — slicing). Catch derived before base (first-fit matching). Every function: at least basic guarantee. |
For full code examples (correct/incorrect pairs): See references/iron-rules.md
Anti-Pattern Quick Reference
When reviewing C++ code, flag these patterns immediately:
| Code Smell | Risk | Fix |
|---|---|---|
Raw / outside RAII | Leak on exception/early return | / → [Iron #1] |
| Non-virtual dtor + virtual functions | UB on polymorphic delete | → [Iron #3] |
(by value) | Slicing | → [Iron #12] |
| Prevents RVO | → [Iron #10] |
or default capture | Dangling /refs | Explicit captures → [references/move-semantics-lambdas.md] |
| Missing Rule of Five | Double-free / use-after-move | Declare all 5 or use Rule of Zero → [Iron #9] |
for threading | Data race (UB) | → [Iron #11] |
| Virtual call in ctor/dtor | Calls base version silently | Pass data via ctor args → [Iron #5] |
| Redefining non-virtual base func | Static binding confusion | Make it virtual or use different name → [Iron #6] |
| public/protected data members | No encapsulation | Private + accessors → [references/class-design.md] |
Two from same raw ptr | Double control block / double-free | or copy existing → [Iron #8] |
Joinable at scope exit | | RAII thread guard → [references/concurrency.md] |
constants/macros | No scope, no type safety | + functions → [references/class-design.md] |
in C++11 | Deduces , not intended type | Use or explicit type → [references/exceptions-interop.md] |
C-style casts | Hides intent, error-prone | //etc. → [references/exceptions-interop.md] |
Scenario Checklists
Creating a New Class
→ Deep dive: references/class-design.md
- Rule of Zero (no resource mgmt) or Rule of Five (manages resources)
- Polymorphic base → virtual dtor. Non-base → no virtual dtor
- All data members
private
on single-argument constructorsexplicit- Member init lists in declaration order
- If copyable: self-assignment safety (copy-and-swap)
- If movable: move operations marked
noexcept
members → protect withmutable
orstd::mutexstd::atomic- Mark all overrides with
override
or= delete
each special member explicitly= default
Managing Resources
→ Deep dive: references/resource-management.md
- Every resource has an RAII owner
- No raw
/new
outside RAII wrappersdelete
/make_unique
over directmake_sharednew
(default) vsunique_ptr
(only when truly shared)shared_ptr
to break cycles or non-owning observationweak_ptr
→new[]
form matchdelete[]- New-ed objects into smart pointers in standalone statements
- Smart pointer members in ctors → safe partial-construction cleanup
Designing Inheritance
→ Deep dive: references/inheritance-templates.md
- Public inheritance = "is-a" — every base operation valid for derived
- Pure virtual = interface. Virtual = interface + default. Non-virtual = invariant
- Never redefine non-virtual functions or inherited default params
on all overrides.override
for hidden overloadsusing Base::func;- Prefer composition over inheritance for "has-a" / "implemented-in-terms-of"
- Consider NVI (public non-virtual → private virtual)
- Make non-leaf classes abstract to prevent slicing
- Never pass arrays polymorphically —
vector<unique_ptr<Base>>
Using Move Semantics
→ Deep dive: references/move-semantics-lambdas.md
on rvalue refs,std::move
on universal refsstd::forward- Apply on last use of parameter only
- Never
a return value — inhibits RVOstd::move
on const → silently copiesstd::move- Mark move operations
noexcept - Don't overload on universal references — use
or tag dispatchenable_if - Know forwarding failures: braced inits, 0/NULL, bitfields, overloaded names
- In generic code: assume moves may not exist or be cheap
Writing Templates
→ Deep dive: references/inheritance-templates.md
before nested dependent type namestypename- Access templatized base class names via
,this->
, or explicit qualificationusing - Factor parameter-independent code out of templates (prevent bloat)
- Member function templates for generalized copy/assignment
- Friend functions inside templates for implicit conversions
- Traits + tag dispatch for compile-time algorithm selection
Concurrent Code
→ Deep dive: references/concurrency.md
for thread safety.std::atomic
for hardware onlyvolatile- Prefer
(task-based) overstd::asyncstd::thread
if asynchronicity is essentialstd::launch::async- RAII wrapper for
(must be unjoinable before destruction)std::thread - Protect
members inmutable
functions with mutex/atomicconst - Last
fromstd::future
blocks on destructionasync
/promise<void>
for one-shot event signalingfuture<void>
Performance Review
→ Deep dive: references/performance.md
- Profile first (80-20 rule). Never optimize blindly
- Postpone variable definitions — define at point of use
- Minimize casting — avoid
in hot pathsdynamic_cast - Avoid returning handles (refs/ptrs) to object internals
- Limit inlining to small, frequently-called functions
- Reduce compilation dependencies (Pimpl, interface classes)
- Facilitate RVO: return by name, never
std::move
overemplace
when constructing in-placepush_back- Mark move/swap
. Prefernoexcept
over+=
in hot paths+
Exception Safety
→ Deep dive: references/exceptions-interop.md
- At least basic guarantee (no leaks, valid state)
- Destructors never throw
- Catch by reference, derived before base
- RAII for all resources — stack unwinding handles cleanup
- Copy-and-swap for strong guarantee
- Exceptions for exceptional conditions only (throwing is slow)
only when genuinely guaranteednoexcept
Strong Recommendations — Quick Summary
These significantly improve code quality. Follow unless there's a documented reason not to.
| Topic | Key Rules |
|---|---|
| const/constexpr [EC-2,3, EMC-15] | for compile-time constants. on parameters, return types, member functions. No . |
| Initialization [EC-4, EMC-7,8] | Member init lists in declaration order. not 0/NULL. Know vs differences. |
| Interfaces [EC-18,20,23,24] | Easy to use correctly, hard to misuse. Pass-by-ref-to-const. Non-member non-friend for encapsulation. Non-member for symmetric type conversions. |
| Scoped enums [EMC-10] | — no namespace pollution, no implicit conversions. |
| = delete [EMC-11] | Compile-time errors, works on any function. Declare . |
| override [EMC-12] | Catches signature mismatches. Always use it on every override. |
| noexcept [EMC-14] | Critical for move ops and swap. Enables optimizations. |
| auto [EMC-5,6] | Prefer auto. Beware proxy types — use idiom. |
| Non-throwing swap [EC-25] | Member swap + non-member in same namespace for ADL. |
| Pimpl [EC-31, EMC-22] | Reduce compilation dependencies. Define special members in .cpp. |
For detailed guidance and code examples on each topic: See the relevant references/ file linked above.
Good to Know — Quick Summary
| Topic | Key Rules |
|---|---|
| Type deduction [EMC-1–4] | Template deduction 3 cases. + braced init → . for return types. |
| Modern syntax [EMC-9,13] | over . / for read-only iteration. |
| Operators [EC-10,24, MEC-6,22] | Assignment returns . then in terms of . Prefix preferred. Non-member for conversions. |
| Lazy/eager eval [MEC-17,18] | Lazy: COW, deferred fetch. Eager: caching, prefetching. |
| Custom new/delete [EC-49–52] | Only when measured need. Follow conventions. Match placement forms. |
| TMP/traits [EC-47,48] | Traits + tag dispatch for compile-time selection. TMP for zero-cost abstractions. |
| C interop [MEC-34] | , no mixed new/free, POD structs, catch at boundary. |
| Temporaries [MEC-19–21] | Arise from implicit conversions and return-by-value. Overload common types. constructors. |