Menu
Coddy logo textTech

Règle des trois / cinq / zéro

Fait partie de la section Programmation Orientée Objet du Journey C++ de Coddy. Leçon 25 sur 104.

Lorsque votre classe gère des ressources comme de la mémoire dynamique, vous avez appris que vous devez définir un destructeur personnalisé, un constructeur de copie et un constructeur de déplacement. Mais il existe un principe directeur qui vous aide à décider quelles fonctions membres spéciales implémenter : la règle des trois, des cinq et du zéro.

La règle des trois stipule que : si vous définissez l’un de ces trois éléments, vous devez tous les définir :

  • Destructeur
  • Constructeur de copie
  • Opérateur d’affectation par copie

La règle des cinq étend ce principe au C++ moderne en ajoutant les opérations de déplacement :

  • Destructeur
  • Constructeur de copie
  • Opérateur d’affectation par copie
  • Constructeur de déplacement
  • Opérateur d’affectation par déplacement
class Buffer {
    int* data;
    size_t size;
public:
    Buffer(size_t s) : size(s), data(new int[s]) {}
    
    ~Buffer() { delete[] data; }                          // 1. Destructeur
    Buffer(const Buffer& other);                          // 2. Constructeur de copie
    Buffer& operator=(const Buffer& other);               // 3. Affectation par copie
    Buffer(Buffer&& other) noexcept;                      // 4. Constructeur de déplacement
    Buffer& operator=(Buffer&& other) noexcept;           // 5. Affectation par déplacement
};

La Rule of Zero est l’approche la plus simple : si votre classe ne gère pas directement de ressources, ne définissez aucune de ces fonctions. Laissez le compilateur les générer, ou utilisez des pointeurs intelligents et des conteneurs standard qui gèrent les ressources à votre place.

class Player {
    std::string name;              // std::string gère sa propre mémoire
    std::vector<int> scores;       // std::vector gère ses ressources
public:
    Player(std::string n) : name(n) {}
    // Aucun destructeur, ni fonctions de copie ou de move n'est nécessaire !
};

Le respect de ces règles évite les bogues tels que les doubles suppressions, les fuites de mémoire et les pointeurs pendants qui surviennent lorsque certaines opérations sont définies, mais que d’autres sont manquantes.

challenge icon

Défi

Facile

Construisons une classe TextBuffer qui respecte la règle des cinq : implémenter les cinq fonctions membres spéciales afin de gérer correctement des données de caractères allouées dynamiquement. Cela montrera comment les opérations de copie et de déplacement fonctionnent ensemble pour créer une classe robuste qui gère ses ressources.

Vous allez créer deux fichiers pour organiser votre code :

  • TextBuffer.h : définir une classe TextBuffer qui stocke du texte dans un tableau de caractères alloué dynamiquement. Votre classe doit comporter :
    • Membres privés : un pointeur char* appelé data pour le contenu textuel, et un size_t length pour la longueur de la chaîne (sans compter le terminateur nul)
    • Un constructeur paramétré qui prend une chaîne C (const char*), alloue de la mémoire, copie le contenu et affiche "TextBuffer created: <text>"
    • Un destructeur qui libère la mémoire (si elle n'est pas nulle) et affiche "TextBuffer destroyed"
    • Un constructeur de copie qui effectue une copie profonde et affiche "TextBuffer copied"
    • Un opérateur d'affectation par copie qui gère l'auto-affectation, libère les données existantes, effectue une copie profonde et affiche "TextBuffer copy-assigned". Retourner *this
    • Un constructeur de déplacement (marqué noexcept) qui transfère la propriété et affiche "TextBuffer moved". Laisser la source dans un état vide valide
    • Un opérateur d'affectation par déplacement (marqué noexcept) qui gère l'auto-affectation, libère les données existantes, transfère la propriété et affiche "TextBuffer move-assigned". Retourner *this
    • Une méthode getText() qui renvoie le texte stocké (renvoyer une chaîne vide "" si data est nul)
    • Une méthode getLength() qui renvoie la longueur
  • main.cpp : démontrer le fonctionnement des cinq fonctions membres spéciales. Lire une chaîne de texte depuis l'entrée, puis :
    • Créer un TextBuffer appelé original avec le texte saisi
    • Créer copied à l'aide du constructeur de copie à partir de original
    • Créer another avec le texte "Temporary"
    • Utiliser l'affectation par copie : another = original
    • Créer moved en construisant par déplacement à partir de original à l'aide de std::move()
    • Créer target avec le texte "Target"
    • Utiliser l'affectation par déplacement : target = std::move(copied)
    • Afficher "--- Final State ---"
    • Afficher "original: <text> (length: <len>)" pour chaque tampon : original, copied, moved, another, target

Après les déplacements, les objets sources (original et copied) doivent afficher un texte vide avec une longueur de 0, tandis que les objets de destination contiennent les données transférées. Cela démontre la règle des cinq en action : les cinq fonctions travaillent ensemble pour garantir une gestion sûre des ressources.

Inclure <cstring> pour les fonctions de chaîne comme strlen et strcpy, ainsi que <utility> pour std::move().

Essayez vous-même

#include <iostream>
#include <string>
#include <utility>
#include "TextBuffer.h"

using namespace std;

int main() {
    string input;
    getline(cin, input);

    // TODO: Créer un TextBuffer appelé 'original' avec le texte d'entrée

    // TODO: Créer 'copied' en utilisant le constructeur de copie à partir de 'original'

    // TODO: Créer 'another' avec le texte "Temporary"

    // TODO: Utiliser l'affectation par copie : another = original

    // TODO: Créer 'moved' par construction par déplacement à partir de 'original' en utilisant std::move()

    // TODO: Créer 'target' avec le texte "Target"

    // TODO: Utiliser l'affectation par déplacement : target = std::move(copied)

    // TODO: Afficher "--- Final State ---"

    // TODO: Afficher l'état de chaque buffer dans ce format :
    // "original: <text> (length: <len>)"
    // Afficher pour : original, copied, moved, another, target

    return 0;
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation Orientée Objet

Entraînez-vous par vous-même : Compilateur C++ en ligne