Communitygithub.com

normes-cpp

Normes de codage C++ basées sur les C++ Core Guidelines (isocpp.github.io). À utiliser lors de l'écriture, la révision ou le remaniement de code C++ pour appliquer des pratiques modernes, sûres et idiomatiques.

Qu'est-ce que normes-cpp ?

Cet ensemble de normes de codage C++ s'inspire directement des *C++ Core Guidelines* officielles et s'adresse aux développeurs travaillant avec C++17, C++20 ou C++23. Il fournit des règles concrètes pour garantir la sécurité des types, une gestion automatique des ressources via RAII, l'immutabilité par défaut, et une expression claire des intentions dans le code. Le guide couvre tous les aspects du développement moderne : philosophie et interfaces, fonctions, classes et hiérarchies, gestion mémoire, expressions et instructions, gestion d'erreurs, constantes, et concurrence. Chaque section présente des règles clés sous forme de tableau, des exemples de code correct et incorrect (DO / DON'T), et des anti-patrons à éviter. L'objectif est de permettre aux équipes et aux outils d'IA (comme les assistants de codage) d'appliquer systématiquement ces principes pour produire un code C++ robuste, maintenable et performant.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/tree/main/skills/cpp-coding-standards

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Normes de codage C++ (C++ Core Guidelines)

Normes de codage complètes pour le C++ moderne (C++17/20/23) dérivées des C++ Core Guidelines. Applique la sécurité des types, la sécurité des ressources, l'immutabilité et la clarté.

Quand les utiliser

  • Écrire du nouveau code C++ (classes, fonctions, templates)
  • Réviser ou remanier du code C++ existant
  • Prendre des décisions architecturales dans des projets C++
  • Appliquer un style cohérent dans une base de code C++
  • Choisir entre des fonctionnalités du langage (ex. : enum vs enum class, pointeur brut vs pointeur intelligent)

Quand ne PAS les utiliser

  • Projets non C++
  • Bases de code C legacy qui ne peuvent pas adopter les fonctionnalités C++ modernes
  • Contextes embarqués / bare-metal où certaines règles entrent en conflit avec des contraintes matérielles (adapter sélectivement)

Principes transversaux

Ces thèmes reviennent dans l'ensemble des directives et en constituent le fondement :

  1. RAII partout (P.8, R.1, E.6, CP.20) : Lier la durée de vie des ressources à celle des objets
  2. Immutabilité par défaut (P.10, Con.1-5, ES.25) : Commencer par const/constexpr ; la mutabilité est l'exception
  3. Sécurité des types (P.4, I.4, ES.46-49, Enum.3) : Utiliser le système de types pour prévenir les erreurs à la compilation
  4. Exprimer l'intention (P.3, F.1, NL.1-2, T.10) : Les noms, types et concepts doivent communiquer le but
  5. Minimiser la complexité (F.2-3, ES.5, Per.4-5) : Un code simple est un code correct
  6. Sémantique de valeur plutôt que de pointeur (C.10, R.3-5, F.20, CP.31) : Privilégier le retour par valeur et les objets de portée

Philosophie et interfaces (P., I.)

Règles clés

RègleRésumé
P.1Exprimer les idées directement dans le code
P.3Exprimer l'intention
P.4Idéalement, un programme devrait être statiquement type-safe
P.5Préférer la vérification à la compilation à la vérification à l'exécution
P.8Ne pas fuir de ressources
P.10Préférer les données immuables aux données mutables
I.1Rendre les interfaces explicites
I.2Éviter les variables globales non-const
I.4Rendre les interfaces précisément et fortement typées
I.11Ne jamais transférer la propriété par un pointeur brut ou une référence
I.23Garder le nombre d'arguments de fonction faible

À FAIRE

// P.10 + I.4 : Interface immuable et fortement typée
struct Temperature {
    double kelvin;
};

Temperature boil(const Temperature& water);

À NE PAS FAIRE

// Interface faible : propriété floue, unités floues
double boil(double* temp);

// Variable globale non-const
int g_counter = 0;  // violation de I.2

Fonctions (F.*)

Règles clés

RègleRésumé
F.1Empaqueter les opérations significatives dans des fonctions soigneusement nommées
F.2Une fonction doit effectuer une seule opération logique
F.3Garder les fonctions courtes et simples
F.4Si une fonction peut être évaluée à la compilation, la déclarer constexpr
F.6Si une fonction ne doit pas lever d'exception, la déclarer noexcept
F.8Préférer les fonctions pures
F.16Pour les paramètres "d'entrée", passer les types peu coûteux à copier par valeur et les autres par const&
F.20Pour les valeurs "de sortie", préférer les valeurs de retour aux paramètres de sortie
F.21Pour retourner plusieurs valeurs "de sortie", préférer retourner une structure
F.43Ne jamais retourner un pointeur ou une référence vers un objet local

Passage de paramètres

// F.16 : Types peu coûteux par valeur, autres par const&
void print(int x);                           // peu coûteux : par valeur
void analyze(const std::string& data);       // coûteux : par const&
void transform(std::string s);               // sink : par valeur (déplacera)

// F.20 + F.21 : Valeurs de retour, pas de paramètres de sortie
struct ParseResult {
    std::string token;
    int position;
};

ParseResult parse(std::string_view input);   // BON : retourne une structure

// MAUVAIS : paramètres de sortie
void parse(std::string_view input,
           std::string& token, int& pos);    // éviter cela

Fonctions pures et constexpr

// F.4 + F.8 : Pure, constexpr si possible
constexpr int factorial(int n) noexcept {
    return (n <= 1) ? 1 : n * factorial(n - 1);
}

static_assert(factorial(5) == 120);

Anti-patrons

  • Retourner T&& depuis des fonctions (F.45)
  • Utiliser va_arg / les variadiques à la C (F.55)
  • Capturer par référence dans des lambdas passées à d'autres threads (F.53)
  • Retourner const T qui inhibe la sémantique de déplacement (F.49)

Classes et hiérarchies de classes (C.*)

Règles clés

RègleRésumé
C.2Utiliser class si un invariant existe ; struct si les membres de données varient indépendamment
C.9Minimiser l'exposition des membres
C.20Si vous pouvez éviter de définir les opérations spéciales, faites-le (Règle de Zéro)
C.21Si vous définissez ou =delete un constructeur de copie/déplacement ou destructeur, gérez-les tous (Règle de Cinq)
C.35Destructeur de classe de base : public virtual ou protected non-virtual
C.41Un constructeur doit créer un objet complètement initialisé
C.46Déclarer les constructeurs à un seul argument explicit
C.67Une classe polymorphique doit supprimer la copie/déplacement publics
C.128Fonctions virtuelles : spécifier exactement un de virtual, override ou final

Règle de Zéro

// C.20 : Laisser le compilateur générer les membres spéciaux
struct Employee {
    std::string name;
    std::string department;
    int id;
    // Pas besoin de destructeur, constructeurs de copie/déplacement ou opérateurs d'affectation
};

Règle de Cinq

// C.21 : Si vous devez gérer une ressource, définissez les cinq
class Buffer {
public:
    explicit Buffer(std::size_t size)
        : data_(std::make_unique<char[]>(size)), size_(size) {}

    ~Buffer() = default;

    Buffer(const Buffer& other)
        : data_(std::make_unique<char[]>(other.size_)), size_(other.size_) {
        std::copy_n(other.data_.get(), size_, data_.get());
    }

    Buffer& operator=(const Buffer& other) {
        if (this != &other) {
            auto new_data = std::make_unique<char[]>(other.size_);
            std::copy_n(other.data_.get(), other.size_, new_data.get());
            data_ = std::move(new_data);
            size_ = other.size_;
        }
        return *this;
    }

    Buffer(Buffer&&) noexcept = default;
    Buffer& operator=(Buffer&&) noexcept = default;

private:
    std::unique_ptr<char[]> data_;
    std::size_t size_;
};

Hiérarchie de classes

// C.35 + C.128 : Destructeur virtuel, utiliser override
class Shape {
public:
    virtual ~Shape() = default;
    virtual double area() const = 0;  // C.121 : interface pure
};

class Circle : public Shape {
public:
    explicit Circle(double r) : radius_(r) {}
    double area() const override { return 3.14159 * radius_ * radius_; }

private:
    double radius_;
};

Anti-patrons

  • Appeler des fonctions virtuelles dans les constructeurs/destructeurs (C.82)
  • Utiliser memset/memcpy sur des types non triviaux (C.90)
  • Fournir des arguments par défaut différents pour une fonction virtuelle et son remplacement (C.140)
  • Rendre les membres de données const ou des références, ce qui supprime le déplacement/la copie (C.12)

Gestion des ressources (R.*)

Règles clés

RègleRésumé
R.1Gérer les ressources automatiquement en utilisant RAII
R.3Un pointeur brut (T*) n'est pas propriétaire
R.5Préférer les objets de portée ; ne pas allouer sur le tas inutilement
R.10Éviter malloc()/free()
R.11Éviter d'appeler new et delete explicitement
R.20Utiliser unique_ptr ou shared_ptr pour représenter la propriété
R.21Préférer unique_ptr à shared_ptr sauf si la propriété est partagée
R.22Utiliser make_shared() pour créer des shared_ptr

Utilisation des pointeurs intelligents

// R.11 + R.20 + R.21 : RAII avec pointeurs intelligents
auto widget = std::make_unique<Widget>("config");  // propriété exclusive
auto cache  = std::make_shared<Cache>(1024);        // propriété partagée

// R.3 : Pointeur brut = observateur non propriétaire
void render(const Widget* w) {  // ne possède PAS w
    if (w) w->draw();
}

render(widget.get());

Patron RAII

// R.1 : L'acquisition de ressources est l'initialisation
class FileHandle {
public:
    explicit FileHandle(const std::string& path)
        : handle_(std::fopen(path.c_str(), "r")) {
        if (!handle_) throw std::runtime_error("Échec d'ouverture : " + path);
    }

    ~FileHandle() {
        if (handle_) std::fclose(handle_);
    }

    FileHandle(const FileHandle&) = delete;
    FileHandle& operator=(const FileHandle&) = delete;
    FileHandle(FileHandle&& other) noexcept
        : handle_(std::exchange(other.handle_, nullptr)) {}
    FileHandle& operator=(FileHandle&& other) noexcept {
        if (this != &other) {
            if (handle_) std::fclose(handle_);
            handle_ = std::exchange(other.handle_, nullptr);
        }
        return *this;
    }

private:
    std::FILE* handle_;
};

Anti-patrons

  • new/delete nus (R.11)
  • malloc()/free() dans du code C++ (R.10)
  • Allocations multiples de ressources dans une seule expression (R.13 -- risque de sécurité d'exception)
  • shared_ptr là où unique_ptr suffit (R.21)

Expressions et instructions (ES.*)

Règles clés

RègleRésumé
ES.5Garder les portées petites
ES.20Toujours initialiser un objet
ES.23Préférer la syntaxe d'initialisation {}
ES.25Déclarer les objets const ou constexpr sauf si la modification est intentionnelle
ES.28Utiliser des lambdas pour l'initialisation complexe de variables const
ES.45Éviter les constantes magiques ; utiliser des constantes symboliques
ES.46Éviter les conversions arithmétiques restrictives/avec perte
ES.47Utiliser nullptr plutôt que 0 ou NULL
ES.48Éviter les casts
ES.50Ne pas enlever const avec un cast

Initialisation

// ES.20 + ES.23 + ES.25 : Toujours initialiser, préférer {}, défaut à const
const int max_retries{3};
const std::string name{"widget"};
const std::vector<int> primes{2, 3, 5, 7, 11};

// ES.28 : Lambda pour l'initialisation constante complexe
const auto config = [&] {
    Config c;
    c.timeout = std::chrono::seconds{30};
    c.retries = max_retries;
    c.verbose = debug_mode;
    return c;
}();

Anti-patrons

  • Variables non initialisées (ES.20)
  • Utiliser 0 ou NULL comme pointeur (ES.47 -- utiliser nullptr)
  • Casts à la C (ES.48 -- utiliser static_cast, const_cast, etc.)
  • Enlever const avec un cast (ES.50)
  • Nombres magiques sans constantes nommées (ES.45)
  • Mélanger l'arithmétique signée et non signée (ES.100)
  • Réutiliser des noms dans des portées imbriquées (ES.12)

Gestion des erreurs (E.*)

Règles clés

RègleRésumé
E.1Développer une stratégie de gestion des erreurs tôt dans la conception
E.2Lever une exception pour signaler qu'une fonction ne peut pas effectuer sa tâche assignée
E.6Utiliser RAII pour éviter les fuites
E.12Utiliser noexcept lorsque lever est impossible ou inacceptable
E.14Utiliser des types définis par l'utilisateur conçus pour cela comme exceptions
E.15Lever par valeur, attraper par référence
E.16Les destructeurs, la désallocation et le swap ne doivent jamais échouer
E.17Ne pas essayer d'attraper toutes les exceptions dans chaque fonction

Hiérarchie d'exceptions

// E.14 + E.15 : Types d'exception personnalisés, lever par valeur, attraper par référence
class AppError : public std::runtime_error {
public:
    using std::runtime_error::runtime_error;
};

class NetworkError : public AppError {
public:
    NetworkError(const std::string& msg, int code)
        : AppError(msg), status_code(code) {}
    int status_code;
};

void fetch_data(const std::string& url) {
    // E.2 : Lever pour signaler un échec
    throw NetworkError("connexion refusée", 503);
}

void run() {
    try {
        fetch_data("https://api.example.com");
    } catch (const NetworkError& e) {
        log_error(e.what(), e.status_code);
    } catch (const AppError& e) {
        log_error(e.what());
    }
    // E.17 : Ne pas tout attraper ici -- laisser les erreurs inattendues se propager
}

Anti-patrons

  • Lever des types intégrés comme int ou des chaînes littérales (E.14)
  • Attraper par valeur (risque de slicing) (E.15)
  • Blocs catch vides qui avalent silencieusement les erreurs
  • Utiliser les exceptions pour le contrôle de flux (E.3)
  • Gestion des erreurs basée sur un état global comme errno (E.28)

Constantes et immutabilité (Con.*)

Toutes les règles

RègleRésumé
Con.1Par défaut, rendre les objets immuables
Con.2Par défaut, rendre les fonctions membres const
Con.3Par défaut, passer les pointeurs et références à const
Con.4Utiliser const pour les valeurs qui ne changent pas après la construction
Con.5Utiliser constexpr pour les valeurs calculables à la compilation
// Con.1 à Con.5 : Immutabilité par défaut
class Sensor {
public:
    explicit Sensor(std::string id) : id_(std::move(id)) {}

    // Con.2 : Fonctions membres const par défaut
    const std::string& id() const { return id_; }
    double last_reading() const { return reading_; }

    // Non-const seulement lorsque la mutation est nécessaire
    void record(double value) { reading_ = value; }

private:
    const std::string id_;  // Con.4 : ne change jamais après la construction
    double reading_{0.0};
};

// Con.3 : Passage par référence constante
void display(const Sensor& s) {
    std::cout << s.id() << ": " << s.last_reading() << '\n';
}

// Con.5 : Constantes à la compilation
constexpr double PI = 3.14159265358979;
constexpr int MAX_SENSORS = 256;

Concurrence et parallélisme (CP.*)

Règles clés

RègleRésumé
CP.2Éviter les courses de données
CP.3Minimiser le partage explicite de données inscriptibles
CP.4Penser en termes de tâches, plutôt que de threads
CP.8Ne pas utiliser volatile pour la synchronisation
CP.20Utiliser RAII, jamais de lock()/unlock() nus
CP.21Utiliser std::scoped_lock pour acquérir plusieurs mutex
CP.22Ne jamais appeler du code inconnu en détenant un verrou
CP.42Ne pas attendre sans condition
CP.44Se souvenir de nommer vos lock_guard et unique_lock
CP.100Ne pas utiliser la programmation sans verrou sauf si absolument nécessaire

Verrouillage sécurisé

// CP.20 + CP.44 : Verrous RAII, toujours nommés
class ThreadSafeQueue {
public:
    void push(int value) {
        std::scoped_lock lock(mutex_);  // CP.44 : lock est nommé
        queue_.push(value);
        cond_.notify_one();
    }

private:
    std::queue<int> queue_;
    std::mutex mutex_;
    std::condition_variable cond_;
};

Communication thread-safe

// CP.42 : Toujours utiliser une variable de condition pour attendre
std::mutex mtx;
std::condition_variable cv;
bool ready{false};

void worker() {
    std::unique_lock lock(mtx);
    cv.wait(lock, [] { return ready; });  // CP.42 : ne pas attendre sans condition
    // Effectuer le travail
}

void signal() {
    {
        std::scoped_lock lock(mtx);
        ready = true;
    }
    cv.notify_one();
}

Anti-patrons

  • volatile pour la synchronisation (CP.8)
  • Utiliser lock()/unlock() sans RAII (CP.20)
  • Attendre en boucle sans variable de condition (CP.42)
  • Verrous non nommés (CP.44)
  • Programmation sans verrou sans compréhension approfondie (CP.100)
  • Passage de données entre threads avec des courses de données non intentionnelles (CP.2)

Nuages et attendant

Anti-patrons

  • Utiliser volatile pour la synchronisation (CP.8)
  • Utiliser lock()/unlock() sans RAII (CP.20)
  • Attendre en boucle sans variable de condition (CP.42)
  • Verrous non nommés (CP.44)
  • Programmation sans verrou sans compréhension approfondie (CP.100)
  • Passage de données entre threads avec des courses de données non intentionnelles (CP.2)

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

Skills associés