January 29, 2026 (6mo ago) — last updated August 11, 2026 (7d ago)

Classes vs Structs — Guide de performance

Comparez classes et structs en C#, Swift et C++ et découvrez quand préférer l’un pour réduire la GC, améliorer la localité de cache et maximiser les performances.

← Back to blog
Cover Image for Classes vs Structs — Guide de performance

La différence essentielle entre classes et structs tient à la sémantique : les classes sont des types par référence et les structs sont des types par valeur. Cette distinction affecte la mémoire, la copie et les performances. Comprendre et appliquer ces règles vous aidera à réduire la pression sur le ramasse‑miettes, améliorer la localité de cache et écrire du code plus rapide et plus sûr.

Classes vs Structs — Guide du développeur sur les performances

Résumé : Comparez classes et structs en C#, Swift et C++ et apprenez quand choisir l’un ou l’autre pour réduire la GC, améliorer la localité de cache et maximiser les performances.

Introduction

La différence essentielle entre classes et structs tient à la sémantique : les classes sont des types par référence et les structs sont des types par valeur12. Cette distinction influence la disposition en mémoire, le comportement à la copie et les performances à l'exécution. Maîtriser ces choix permet d’écrire du code plus prévisible, plus rapide et plus facile à maintenir.

Comprendre la différence fondamentale

Quand vous instanciez une classe, la variable contient une référence vers un objet alloué sur le tas. Copier cette variable copie la référence ; plusieurs références peuvent pointer vers le même objet, donc modifier l’objet via une référence est visible depuis les autres. Cette sémantique par référence est idéale pour des entités qui ont une identité1.

Un struct contient les données elles‑mêmes. Copier un struct produit une copie indépendante ; modifier la copie n’affecte pas l’original. Les structs conviennent bien aux valeurs simples et immuables, souvent stockées sur la pile ou en ligne dans des tableaux, ce qui améliore la localité de cache12.

Pour approfondir l’encapsulation et la conception orientée objet, voyez notre guide sur l’encapsulation : https://cleancodeguy.com/blog/object-oriented-encapsulation.

Diagramme illustrant les Structs stockés sur la pile et les Classes référencées depuis la pile vers le tas.

Comparaison rapide : types par référence vs types par valeur

CaractéristiqueClasse (type par référence)Struct (type par valeur)
Emplacement en mémoireTas ; objet référencé par pointeur.Pile ou en ligne ; la variable contient les données.
AffectationCopie la référence, pas l’objet.Copie la valeur entière.
Durée de vieGérée par le ramasse‑miettes ou suppression manuelle.Désalloué hors portée ou en ligne.
Identité vs valeurA une identité ; plusieurs références peuvent pointer vers la même instance.Représente une valeur ; l’égalité est souvent basée sur les données.

Utilisez une classe lorsque vous avez besoin d’une identité partagée. Utilisez un struct lorsque vous voulez une valeur simple, autonome et sans effets secondaires.

Cette base informe des compromis de performance — allocation sur le tas vs pile, localité de cache et pression sur le ramasse‑miettes — que nous détaillons ci‑dessous.

Comment l’allocation mémoire dicte la vitesse

La disposition en mémoire affecte l’efficacité du processeur, le débit et la latence. Accéder à une classe implique généralement une indirection : un pointeur sur la pile référence des données sur le tas. Cette indirection ajoute un coût et peut nuire au comportement du cache. Les structs, stockés directement là où la variable vit, évitent souvent cette indirection et permettent des dispositions mémoire plus compactes et une meilleure localité de cache5.

Diagramme comparant l'allocation mémoire Struct/Pile et Class/Tas, mettant en évidence la mémoire contiguë, le ramasse‑miettes, et les différences de vitesse.

Coûts du ramasse‑miettes

Les objets sur le tas sont soumis au ramasse‑miettes. Les cycles GC peuvent suspendre l’exécution et augmenter la latence dans des systèmes temps réel ou à haut débit. L’allocation fréquente d’objets de courte durée augmente la pression sur le GC et la charge CPU. Utiliser des types par valeur pour de nombreux petits objets réduit le churn du tas et le travail du ramasse‑miettes3.

L’allocation sur le tas ajoute un coût potentiel lié au ramasse‑miettes. Les structs évitent ce surcoût lorsqu’ils restent non boxés.

Réduire les allocations dans les chemins chauds peut lisser les performances à l’exécution et diminuer les pauses GC observables en production3.

Localité du cache et débit

Les processeurs modernes dépendent fortement des caches. Les dispositions séquentielles — comme des tableaux de structs — améliorent les hits de cache et le débit. Des allocations séparées sur le tas pour chaque instance de classe dispersent les données en mémoire, augmentant les misses de cache et ralentissant le traitement. Pour les boucles serrées et les pipelines de données, les structures contiguës de valeurs offrent un avantage notable en débit et latence5.

Le piège du boxing

Le boxing survient lorsqu’un type par valeur est converti en type par référence, par exemple en étant placé dans une collection qui attend des objets. Le boxing alloue un objet sur le tas et copie la valeur dedans, annulant les avantages du struct et augmentant la charge sur le GC. Éviter le boxing est une règle clé pour profiter des bénéfices des types par valeur4.

Comment les langages diffèrent : C#, C++ et Swift

Différents langages imposent des conventions et offrent des capacités différentes. Connaître les règles de la plateforme évite d’appliquer aveuglément des règles d’un langage à un autre.

Diagramme comparant les caractéristiques des langages de programmation C#, C++ et Swift, en se concentrant sur les types par référence vs valeur et la flexibilité des objets.

C# : distinction claire référence vs valeur

En C#, class = type par référence et struct = type par valeur. Utilisez des classes pour des entités avec identité (par exemple Customer ou DatabaseConnection) et des structs pour de petites valeurs immuables (par exemple Point, Color). Garder les structs petits et immuables évite des bugs subtils et des frais de copie1.

Les erreurs courantes incluent la création de structs volumineux ou mutables ; les deux peuvent mener à des comportements surprenants ou à des régressions de performance. Suivez la règle de conserver les structs petits et immuables lors d’optimisations en C#1.

C++ : convention plutôt que restriction

En C++, la seule différence syntaxique entre struct et class est l’accessibilité par défaut. Les deux peuvent être alloués sur la pile ou le tas, avoir des méthodes et supporter l’héritage. La convention est d’utiliser struct pour des agrégats de données simples et class pour des objets encapsulés et la gestion RAII des ressources.

Cette flexibilité signifie que les développeurs C++ doivent s’appuyer sur des conventions et des choix de conception plutôt que sur des distinctions valeur/référence imposées par le langage. Pour des conseils sur le polymorphisme et l’héritage, voyez nos notes de conception C++ : https://cleancodeguy.com/blog/polymorphism-vs-inheritance.

Swift : préférence pour la valeur

Swift encourage la préférence des structs pour la plupart des types personnalisés. Les structs en Swift supportent les méthodes, les extensions et la conformité aux protocoles, ce qui les rend puissants tout en restant des valeurs par défaut. Choisissez les classes uniquement lorsque la sémantique par référence, l’identité ou l’interopérabilité Objective‑C est requise2.

Cette orientation vers la valeur favorise l’immuabilité et une meilleure compréhension du flux de données, en particulier en code concurrent.

Quand choisir un struct pour une efficacité maximale

Les structs conviennent pour de petits paquets de données immuables dont l’identité est définie par la valeur. Exemples typiques :

  • Données géométriques : Point2D ou RGBColor
  • Valeurs financières : Money (amount + currency)
  • Petits DTO utilisés dans des pipelines à haut débit

Une règle pratique de taille est la règle « 16–32 octets » : si les champs d’un struct tiennent dans cette plage, le coût de copie est modeste et souvent moins cher que l’allocation sur le tas. Si un struct devient plus grand ou doit être mutable, une classe est probablement un meilleur choix5.

Guide sur le choix de structs pour de petites données de type valeur comme RGB, Point 2D et Money, avec une directive de 16 octets.

Règles d’immuabilité et de taille

  • Préférez les structs immuables : les valeurs doivent être créées une fois et remplacées plutôt que mutées.
  • Gardez les structs petits : copier fréquemment de gros structs peut être plus coûteux que passer des références.

Ces règles évitent des bugs silencieux dus aux copies mutables et des pièges de performance liés aux copies excessives ou au boxing.

Pièges courants et refactorings

Deux problèmes fréquents sont les structs mutables et le boxing excessif.

Les structs mutables mènent à des comportements surprenants car les modifications n’affectent qu’une copie. Refactorez les structs mutables en structs immuables qui renvoient de nouvelles instances pour les changements d’état.

Le boxing se produit implicitement dans de nombreuses API et collections ; identifiez et supprimez les points chauds de boxing pour préserver les avantages de performance des structs4.

Exemple : refactoriser un Point mutable en struct immuable (C#)

// PITFALL: Mutable struct
public struct MutablePoint
{
    public int X { get; set; }
    public int Y { get; set; }

    public void Move(int dx, int dy)
    {
        X += dx;
        Y += dy;
    }
}

// REFACTOR: Immutable struct
public readonly struct ImmutablePoint
{
    public int X { get; }
    public int Y { get; }

    public ImmutablePoint(int x, int y)
    {
        X = x;
        Y = y;
    }

    public ImmutablePoint MovedBy(int dx, int dy)
    {
        return new ImmutablePoint(X + dx, Y + dy);
    }
}

Ce refactoring rend l’intention explicite et élimine la corruption d’état accidentelle. Pour plus de pratiques de clean coding, consultez notre guide des principes : https://cleancodeguy.com/blog/clean-coding-principles.

FAQ concise

Q1 : Quand devrais‑je préférer un struct à une classe ?

Préférez un struct si le type est petit, immuable et représente une valeur plutôt qu’une identité. Les structs sont parfaits pour des points, des couleurs et de petits DTO.

Q2 : Quels pièges de performance dois‑je surveiller ?

Évitez les structs mutables, les structs volumineux (coût de copie) et le boxing en objets sur le tas — ces facteurs annulent les bénéfices des types par valeur4.

Q3 : Comment les différences de langage affectent‑elles mon choix ?

Suivez les idiomes du langage : C# impose valeur vs référence ; C++ repose sur des conventions ; Swift favorise la valeur par défaut. Apprenez les règles de la plateforme avant d’appliquer des modèles multi‑langages12.


Chez Clean Code Guy, nous aidons les équipes à appliquer ces principes sur de vrais codebases. Nos nettoyages de code et refactorings AI‑ready rendent les logiciels plus rapides, plus sûrs et plus faciles à maintenir. Visitez https://cleancode.com pour en savoir plus.

Questions rapides (Q&A)

Q : Un struct rendra‑t‑il toujours mon code plus rapide ?

R : Pas toujours. Les structs aident quand ils restent petits, immuables et non boxés. Pour de grosses données ou une sémantique d’identité, une classe est souvent plus adaptée.

Q : Comment détecter le boxing dans mon code ?

R : Recherchez les conversions implicites vers des types objets, l’utilisation d’API non génériques ou les collections non typées. Les outils d’analyse statique et les profils d’allocation montrent les allocations inattendues3.

Q : Quelle est la règle pratique pour la taille d’un struct ?

R : Visez des structs de l’ordre de 16–32 octets maximum pour éviter un coût de copie trop important ; au‑delà, préférez une référence5.

1.
Microsoft Docs, “Choosing between classes and structs,” https://learn.microsoft.com/en-us/dotnet/standard/choosing-between-class-and-struct
2.
Apple Developer Documentation, “Structures and Classes,” https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html
4.
5.
NDepend Blog, “Class vs Struct in C#: Making Informed Choices,” https://blog.ndepend.com/class-vs-struct-in-c-making-informed-choices/
← Back to blog
🙋🏻‍♂️

L’IA écrit du code.
Vous le faites durer.

À l’ère de l’accélération de l’IA, le code propre n’est pas seulement une bonne pratique — c’est la différence entre les systèmes qui évoluent et les codebases qui s’effondrent sous leur propre poids.