Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Programmation robuste

throw

Un exemple d’utilisation de throw :

int ScoreHandler::sumScores(std::vector<int> scores) {
    if(scores.empty()) {
        throw std::runtime_error("Cannot sum without scores.");
    }

    int sum = 0;
    for (int score : scores) {
        sum += score;
    }
    return sum;
}

Exemple de code avec nullptr :

std::string* TeamHandler::findTeamNameFromPlayer(std::vector<Team> teams, std::string playerName) {
    int index = 0;
    while (index < teams.size() && !teams[index].containsPlayer(playerName)) {
        index++;
    }

    if (index >= teams.size()) {
        return nullptr;
    }

    return &teams[index].getName(); // Si getName renvoie std:string&
}

void displayWinner(std::vector<int> scores) {
    int highestScore = ScoreHandler::findHighestScore(scores);

    if (highestScore != nullptr) {
        std::string* playerName = PlayerHandler::findPlayerNameFromScore(*highestScore);

        if (playerName != nullptr) {
            std::string* teamName = TeamHandler::findTeamNameFromPlayer(*playerName);

            if (teamName != nullptr) {
                std::cout << *playerName << " from team " << *teamName << " won with score " << *highestScore << std::endl;
            } else {
                std::cout << "Team not found." << std::endl;
            }
        } else {
            std::cout << "Player not found." << std::endl;
        }
    } else {
        std::cout << "No score found." << std::endl;
    }
}

Une solution avec throw :

std::string TeamHandler::findTeamNameFromPlayer(std::vector<Team> teams, std::string playerName) {
    int index = 0;
    while (index < teams.size() && !teams[index].containsPlayer(playerName)) {
        index++;
    }

    if (index >= teams.size()) {
        throw std::runtime_error("Team not found.");
    }

    return teams[index].getName(); 
}

void displayWinner(std::vector<int> scores) {
    int highestScore = ScoreHandler::findHighestScore(scores);
    std::string playerName = PlayerHandler::findPlayerNameFromScore(highestScore);
    std::string teamName = TeamHandler::findTeamNameFromPlayer(playerName);
    std::cout << playerName << " from team " << teamName << " won with score " << highestScore << std::endl;
}

Il faudra attraper l’erreur plus tard et afficher le message correspondant.

try, catch

Exemple de try, catch :

void Application::run() {
    // ...

    // Application loop
    while (...) {
        try {
            // Call to TeamHandler::findTeamNameFromPlayer

        } catch (const std::runtime_error& error) {
            std::cout << error.what() << std::endl; // Example output: "Team not found".
        }
    }
}

Input validation

Un type d’erreur récupérable est des erreurs d’entrée de l’utilisateur.
Dans ce cas, nous voulons faire de la validation de l’entrée utilisateur avant de passer à l’étape suivante.

#include "input-reader.h"
#include <istream> // for std::istream
#include <sstream> // for std::istringstream
#include <string>
#include <iostream>
#include <stdexcept> // for std::invalid_argument
 
std::string InputReader::requestInput(const std::string &message, bool (*isValid)(std::istream&), const std::string &errorMessage) {
    std::string input;
    int numberAttempts = 0;
    bool isInputValid = false;

    // Nous limitons le nombre d'essais pour éviter les boucles infinies
    while (numberAttempts < MAX_INPUT_ATTEMPTS && !isInputValid) {
        // Le message est affiché pour demander à l'utilisateur de fournir une entrée
        std::cout << message;

        // Nous récupérons la ligne d'entrée 
        std::getline(std::cin, input);

        // Nous validons l'entrée (en tant que stream)
        std::istringstream inputStream(input);
        isInputValid = isValid(inputStream);

        if (!isInputValid) {
            numberAttempts++;

            // Nous affichons le message d'erreur qui aide l'utilisateur à fournir une entrée valide
            std::cout << errorMessage << std::endl;
            std::cout << MAX_INPUT_ATTEMPTS - numberAttempts << " attempts left." << std::endl;
        }
    }
    
    // Si le nombre d'essais maximum est atteint 
    // et que l'entrée n'est toujours pas valide, nous levons une exception
    if (!isInputValid) {
        throw std::invalid_argument("Maximum number of attempts reached.");
    }

    return input;
}

Exemple d’utilisation :

// Suppose a score is an integer between MIN_SCORE and MAX SCORE defined in input-reader.h
bool InputReader::isValidScore(std::istream& inputStream) {
    int number;
    char remainingCharacter;

    bool isValidInput = !(inputStream >> number).fail();
    bool isValidRange = isValidInput && number >= MIN_SCORE && number <= MAX_SCORE;
    bool containsOnlyNumber = isValidInput && (inputStream >> remainingCharacter).fail();
    return isValidRange && containsOnlyNumber;
}

int InputReader::requestScore() {
    std::string input = requestInput("Enter the player's score: ", InputReader::isValidScore, "Please enter an integer between 0 and 100.");
    return std::stoi(input); // stoi = string to integer
}

Fatal errors

Dans main.cpp, nous pouvons attraper les erreurs fatales qui arrêtent le programme dont std::invalid_argument("Maximum number of attempts reached.") entre autre.

#include "application.h"
#include <iostream>
#include <exception>

int main() {
    try {
        Application application;
        application.run();
    } catch (const std::exception& error) {
        std::cout << "Fatal error: " << error.what() << std::endl;
        return 1; // Exit code 1 for failures
    }
    return 0;
}