modern-cpp-refactor | Skill Performance & Reviews | TopRankSkills

TopRank Skills

Home / Skills / tools / modern-cpp-refactor

modern-cpp-refactor

maintained by Mq-b

star 15 account_tree 10 verified_user MIT License
bolt View GitHub

name: modern-cpp-refactor description: "Modern C++ refactoring intelligence. Scans and modernizes legacy C/C++98/11 code to C++17/20 standards. Detects: raw pointers, manual memory, C-style arrays, old containers, manual loops. Replaces with: smart pointers, RAII, std::array/vector, ranges, std::format, structured bindings, auto, constexpr, concepts, std::optional, std::variant. Actions: scan, analyze, refactor, modernize, upgrade, review, check C++ code. Patterns: memory leaks, null checks, iterator loops, string formatting, error handling, ownership semantics."

Modern C++ Refactor - Code Modernization Intelligence

Automated detection and refactoring of legacy C/C++98/11 code to modern C++17/20 standards using smart pointers, ranges, std::format, and contemporary best practices.

Prerequisites

Check if Python is installed:

python3 --version || python --version

If Python is not installed, install it based on user's OS:

macOS:

brew install python3

Ubuntu/Debian:

sudo apt update && sudo apt install python3

Windows:

winget install Python.Python.3.12

How to Use This Skill

When user requests C++ code refactoring, modernization, or asks to write new C++ code, follow this workflow:

Step 0: Check Project Coding Standards (CRITICAL)

ALWAYS check for .clang-format file first:

# Check if .clang-format exists in project
ls .clang-format || find . -name ".clang-format" -type f

If .clang-format exists:

  • STRICTLY FOLLOW the formatting rules defined in it
  • Do NOT deviate from the project's established style
  • Use the same brace style, indentation, spacing as configured
  • After refactoring, format code with: clang-format -i <file>

If .clang-format does NOT exist:

  • Follow Modern C++ best practices from this guide
  • Consider creating a .clang-format for consistency

Also check for other project standards:

  • CMakeLists.txt or Makefile for C++ standard version (C++17/20/23)
  • CONTRIBUTING.md or STYLE.md for coding guidelines
  • Existing code patterns in the codebase

Step 1: Scan for Legacy Patterns

Use the scanner script to detect legacy C++ patterns:

python3 .claude/skills/modern-cpp-refactor/scripts/scan.py <file_or_directory> [--detailed]

This will identify:

  • Raw pointers and manual memory management
  • C-style arrays and strings
  • Old-style casts
  • Manual loops vs ranges
  • Printf/sprintf vs std::format
  • NULL vs nullptr
  • typedef vs using

Step 2: Analyze Code Context

Before refactoring, understand:

  • C++ Standard: What standard is currently used? (Check CMakeLists.txt, Makefile, compiler flags)
  • Dependencies: Are there third-party libraries that require specific patterns?
  • Ownership: Who owns the memory? (unique_ptr, shared_ptr, or value semantics?)
  • Performance: Is this hot path code? (Consider move semantics, perfect forwarding)

Step 3: Apply Modern C++ Transformations

Follow the modernization rules below to refactor code systematically.


Modern C++ Transformation Rules

Memory Management

Legacy Pattern Modern C++17/20 When to Use
new / delete std::make_unique<T>() Exclusive ownership
new / delete std::make_shared<T>() Shared ownership
Raw pointer parameters T& or std::span<T> Non-owning access
new T[size] std::vector<T> or std::array<T, N> Dynamic/fixed arrays
Manual delete[] Automatic via RAII containers Always
malloc / free std::vector or smart pointers C++ code (never use malloc)

Example:

// Legacy
int* data = new int[100];
// ... use data ...
delete[] data;

// Modern C++17/20
auto data = std::vector<int>(100);
// ... use data ... (automatic cleanup)

// Or for fixed size:
auto data = std::array<int, 100>{};

Raw Pointers to Smart Pointers

Legacy Pattern Modern C++17/20 Reasoning
Widget* ptr = new Widget(); auto ptr = std::make_unique<Widget>(); Exception-safe, RAII
Function returns T* (ownership) Function returns std::unique_ptr<T> Clear ownership transfer
Function accepts T* (ownership) Function accepts std::unique_ptr<T> Clear ownership transfer
Function accepts T* (non-owning) Function accepts T& or T* (document!) Non-null use T&
NULL nullptr Type-safe null

Example:

// Legacy
class Manager {
    Widget* widget;
public:
    Manager() : widget(new Widget()) {}
    ~Manager() { delete widget; }
};

// Modern C++17/20
class Manager {
    std::unique_ptr<Widget> widget;
public:
    Manager() : widget(std::make_unique<Widget>()) {}
    // No destructor needed - automatic cleanup
};

Containers and Arrays

Legacy Pattern Modern C++17/20 Benefits
T arr[N] std::array<T, N> Bounds checking, STL algorithms
T* arr = new T[n] std::vector<T> RAII, dynamic sizing
C-string char* std::string Memory-safe, easier manipulation
char buffer[256] std::string or std::vector<char> No buffer overflow
Manual size tracking .size() method Automatic

Example:

// Legacy
char buffer[256];
sprintf(buffer, "Value: %d", value);

// Modern C++20
auto buffer = std::format("Value: {}", value);

// Modern C++17 (without format)
auto buffer = std::string("Value: ") + std::to_string(value);

Loops and Algorithms

Legacy Pattern Modern C++17/20 Benefits
for (int i = 0; i < n; i++) for (auto& elem : container) Cleaner, less error-prone
Iterator loops Range-based for or ranges More expressive
Manual find loop std::find, std::find_if Standard, optimized
Manual sum loop std::accumulate or ranges Declarative intent
Manual transform loop std::transform or ranges::transform Functional style

Example:

// Legacy
std::vector<int> vec = {1, 2, 3, 4, 5};
for (size_t i = 0; i < vec.size(); i++) {
    vec[i] *= 2;
}

// Modern C++17
for (auto& val : vec) {
    val *= 2;
}

// Modern C++20 (ranges)
#include <ranges>
auto doubled = vec | std::views::transform([](int x) { return x * 2; });

Type Declarations

Legacy Pattern Modern C++17/20 Benefits
Explicit types everywhere auto for obvious types Less typing, easier refactoring
typedef std::vector<int> IntVec using IntVec = std::vector<int> Consistent syntax
Type-specific functions template<typename T> with concepts Type-safe generics
std::pair with .first, .second Structured bindings auto [a, b] Named values

Example:

// Legacy
std::map<std::string, int>::iterator it = myMap.find("key");
if (it != myMap.end()) {
    int value = it->second;
}

// Modern C++17
if (auto it = myMap.find("key"); it != myMap.end()) {
    auto [key, value] = *it;
    // Use key and value directly
}

// Modern C++17 (structured binding)
for (const auto& [key, value] : myMap) {
    // Use key and value directly
}

Error Handling

Legacy Pattern Modern C++17/20 When to Use
Return -1 or nullptr std::optional<T> Operation may fail
Exception + error code std::expected<T, Error> (C++23) or std::optional Expected failures
Multiple return types std::variant<T1, T2> Type-safe union
Boolean + out parameter Return std::optional<T> Cleaner API

Example:

// Legacy
Widget* findWidget(int id) {
    // ... search ...
    if (not_found) return nullptr;
    return widget;
}

// Modern C++17
std::optional<Widget> findWidget(int id) {
    // ... search ...
    if (not_found) return std::nullopt;
    return widget;
}

// Usage:
if (auto widget = findWidget(42)) {
    // Use *widget
}

String Formatting

Legacy Pattern Modern C++17/20 Benefits
sprintf, snprintf std::format (C++20) Type-safe, no buffer overflow
std::stringstream std::format Simpler, faster
Manual string concat std::format or fmt::format Readable

Example:

// Legacy
char buffer[256];
sprintf(buffer, "Name: %s, Age: %d", name.c_str(), age);

// Modern C++20
auto result = std::format("Name: {}, Age: {}", name, age);

// Alternative (C++17 with fmt library):
auto result = fmt::format("Name: {}, Age: {}", name, age);

Casts

Legacy Pattern Modern C++17/20 Safety
C-style cast (Type)value static_cast<Type>(value) Explicit intent
(Type)ptr for pointers dynamic_cast<Type*>(ptr) Runtime type check
Const removal (Type) const_cast<Type>(value) Explicit const violation
reinterpret_cast Avoid or document heavily Dangerous

Initialization

Legacy Pattern Modern C++17/20 Benefits
Type var = Type(args) Type var{args} Uniform initialization
Type var; (uninitialized) Type var{} Zero-initialized
Copy initialization Direct initialization {} No implicit conversions

Example:

// Legacy
std::vector<int> vec = std::vector<int>(10, 5);

// Modern C++17
auto vec = std::vector<int>(10, 5);
// Or even better:
std::vector<int> vec(10, 5);

Const Correctness

Rule Modern C++ Standard
Mark functions const if they don't modify Always
Use const& for read-only parameters For non-primitive types
Use constexpr for compile-time constants C++17/20
Use if constexpr for compile-time branches C++17

Example:

// Legacy
int getValue() { return value; }

// Modern C++17
int getValue() const { return value; }
constexpr int getMax() const { return 100; }

Move Semantics

Legacy Pattern Modern C++17/20 Benefits
Pass by value (copy) Pass by const& No unnecessary copy
Return large objects Return by value (RVO/NRVO) Compiler optimization
Explicit copy std::move for transfer Efficient

Example:

// Modern C++17
class Widget {
    std::vector<int> data;
public:
    // Move constructor
    Widget(Widget&& other) noexcept
        : data(std::move(other.data)) {}

    // Move assignment
    Widget& operator=(Widget&& other) noexcept {
        data = std::move(other.data);
        return *this;
    }
};

Concepts (C++20)

Legacy Pattern Modern C++20 Benefits
Template + SFINAE Concepts Clear constraints, better errors
typename everywhere Concepts with semantic names Self-documenting

Example:

// Legacy
template<typename T>
typename std::enable_if<std::is_integral<T>::value, T>::type
add(T a, T b) { return a + b; }

// Modern C++20
template<std::integral T>
T add(T a, T b) { return a + b; }

// Or with concept:
std::integral auto add(std::integral auto a, std::integral auto b) {
    return a + b;
}

Code Scanning Categories

The scanner will check for these categories:

1. Memory Safety Issues

  • Raw new / delete
  • Manual array allocation
  • Missing delete (potential leaks)
  • malloc / free in C++ code

2. Type Safety Issues

  • C-style casts
  • NULL instead of nullptr
  • Missing const qualifiers
  • Implicit conversions

3. Modernization Opportunities

  • typedef instead of using
  • Manual loops vs ranges
  • std::bind vs lambdas
  • Raw function pointers vs std::function

4. String and I/O Issues

  • C-style strings (char*, char[])
  • sprintf family
  • printf vs std::format

5. Concurrency (if applicable)

  • Raw std::thread without RAII wrapper
  • Manual locking vs std::lock_guard
  • Missing std::atomic for shared data

Pre-Refactor Checklist

Before modernizing code, verify:

  • Identify the target C++ standard (C++17 or C++20)
  • Check if compiler supports required features
  • Understand existing ownership semantics
  • Identify performance-critical sections
  • Check for third-party library constraints
  • Ensure comprehensive test coverage exists
  • Plan incremental refactoring (not all at once)

Post-Refactor Checklist

After modernizing code, verify:

  • All tests still pass
  • No memory leaks (use valgrind/sanitizers)
  • Performance is acceptable (profile if needed)
  • Code compiles with -Wall -Wextra -Werror
  • Smart pointers have correct ownership semantics
  • Move semantics applied where beneficial
  • const correctness maintained
  • No raw new / delete remaining (except special cases)

Example Workflow

User request: "Modernize this C++ class to use C++17/20 features"

AI should:

  1. Scan the code:
python3 .claude/skills/modern-cpp-refactor/scripts/scan.py src/MyClass.cpp --detailed
  1. Analyze findings:

    • Identify legacy patterns (raw pointers, manual loops, etc.)
    • Understand ownership semantics
    • Check for performance implications
  2. Refactor systematically:

    • Replace raw pointers with smart pointers
    • Convert manual loops to range-based or algorithms
    • Use auto for obvious types
    • Apply structured bindings where applicable
    • Replace sprintf with std::format (C++20) or alternatives
    • Add constexpr and const where appropriate
  3. Verify:

    • Compile with modern C++ flags
    • Run tests
    • Check for memory leaks
    • Review performance

Common Anti-Patterns to Avoid

Don't Over-Use Smart Pointers

// Bad: Using unique_ptr for simple value
std::unique_ptr<int> value = std::make_unique<int>(42);

// Good: Just use a value
int value = 42;

Don't Use Shared Ptr Everywhere

// Bad: Shared ownership without need
std::shared_ptr<Widget> widget = std::make_shared<Widget>();

// Good: Unique ownership when possible
auto widget = std::make_unique<Widget>();

Don't Ignore Move Semantics

// Bad: Unnecessary copy
std::vector<int> getData() {
    std::vector<int> result = computeData();
    return result; // Copy
}

// Good: Move semantics (or RVO)
std::vector<int> getData() {
    return computeData(); // Move or RVO
}

Quick Reference: Modern C++ Features by Standard

C++17 Must-Use Features

  • Structured bindings: auto [a, b] = pair;
  • if / switch with initializer: if (auto x = foo(); x > 0)
  • std::optional<T> for maybe-values
  • std::variant<T1, T2> for type-safe unions
  • std::string_view for non-owning string refs
  • Fold expressions in templates
  • Class template argument deduction (CTAD)

C++20 Must-Use Features

  • std::format for string formatting
  • Ranges and views
  • Concepts for template constraints
  • std::span<T> for array views
  • Three-way comparison operator <=>
  • Designated initializers: Point{.x=1, .y=2}
  • consteval for compile-time evaluation

When NOT to Modernize

Sometimes legacy patterns are necessary:

  1. Interfacing with C APIs: May require raw pointers
  2. Performance-critical code: Profile before/after
  3. Third-party library constraints: API may require specific types
  4. Incremental migration: Don't refactor everything at once
  5. Platform limitations: Embedded systems may lack std library

Additional Resources


Default Behavior

When user asks you to write NEW C++ code (not just refactor):

STEP 0 - ALWAYS CHECK FIRST:

  • Check for .clang-format file - If it exists, STRICTLY follow its formatting rules

THEN follow these modern C++ standards:

  1. Always use C++17/20 standards by default
  2. Never use raw new / delete - use smart pointers or RAII containers
  3. Prefer std::format (C++20) or fmt library over sprintf
  4. Use auto for obvious types
  5. Use range-based for instead of manual index loops
  6. Use std::optional for maybe-values
  7. Use structured bindings for pairs/tuples/structs
  8. Mark functions const and constexpr when applicable
  9. Use nullptr never NULL
  10. Use using never typedef
  11. Respect project's .clang-format for all code formatting decisions

This ensures all generated code follows both modern C++ best practices AND the project's established coding standards.

chat Comments (0)

chat_bubble_outline

No comments yet. Be the first to share your thoughts!

Skill Details

GitHub Stars 15
GitHub Forks 10
Created Mar 2026
Last Updated 3个月前
tools tools automation tools

Related Skills

specs-gen
chevron_right
glm-coding-agent
chevron_right
creating-pr
chevron_right
writing-skills
chevron_right
reviewing-pr
chevron_right

Build your own?

Join 12,000+ developers contributing to the Claude ecosystem.