172 votes

Comment lancer des exceptions std::avec des messages variables ?

Voici un exemple de ce que je fais souvent lorsque je veux ajouter des informations à une exception :

std::stringstream errMsg;
errMsg << "Could not load config file '" << configfile << "'";
throw std::exception(errMsg.str().c_str());

Y a-t-il une façon plus agréable de le faire ?

234voto

Kerrek SB Points 194696

Les exceptions standard peuvent être construites à partir d'un std::string :

#include <stdexcept>

char const * configfile = "hardcode.cfg";
std::string const anotherfile = get_file();

throw std::runtime_error(std::string("Failed: ") + configfile);
throw std::runtime_error("Error: " + anotherfile);

Notez que la classe de base std::exception peut no ne peut être construit ainsi ; vous devez utiliser l'une des classes concrètes, dérivées.

60voto

Torsten Points 2778

Voici ma solution :

#include <stdexcept>
#include <sstream>

class Formatter
{
public:
    Formatter() {}
    ~Formatter() {}

    template <typename Type>
    Formatter & operator << (const Type & value)
    {
        stream_ << value;
        return *this;
    }

    std::string str() const         { return stream_.str(); }
    operator std::string () const   { return stream_.str(); }

    enum ConvertToString 
    {
        to_str
    };
    std::string operator >> (ConvertToString) { return stream_.str(); }

private:
    std::stringstream stream_;

    Formatter(const Formatter &);
    Formatter & operator = (Formatter &);
};

Exemple :

throw std::runtime_error(Formatter() << foo << 13 << ", bar" << myData);   // implicitly cast to std::string
throw std::runtime_error(Formatter() << foo << 13 << ", bar" << myData >> Formatter::to_str);    // explicitly cast to std::string

31voto

Neel Basu Points 4371

Il existe différentes exceptions telles que runtime_error , range_error , overflow_error , logic_error etc. Vous devez passer la chaîne de caractères dans son constructeur, et vous pouvez concaténer ce que vous voulez à votre message. C'est juste une opération de chaîne de caractères.

std::string errorMessage = std::string("Error: on file ")+fileName;
throw std::runtime_error(errorMessage);

Vous pouvez également utiliser boost::format comme ça :

throw std::runtime_error(boost::format("Error processing file %1") % fileName);

17voto

Maxim Yegorushkin Points 29380

La classe suivante pourrait s'avérer très utile :

struct Error : std::exception
{
    char text[1000];

    Error(char const* fmt, ...) __attribute__((format(printf,2,3))) {
        va_list ap;
        va_start(ap, fmt);
        vsnprintf(text, sizeof text, fmt, ap);
        va_end(ap);
    }

    char const* what() const throw() { return text; }
};

Exemple d'utilisation :

throw Error("Could not load config file '%s'", configfile.c_str());

15voto

Shreevardhan Points 19

Utiliser l'opérateur littéral de chaîne si C++14 ( operator ""s )

using namespace std::string_literals;

throw std::exception("Could not load config file '"s + configfile + "'"s);

ou définissez votre propre définition si vous êtes en C++11. Par exemple

std::string operator ""_s(const char * str, std::size_t len) {
    return std::string(str, str + len);
}

Votre déclaration de lancement ressemblera alors à ceci

throw std::exception("Could not load config file '"_s + configfile + "'"_s);

qui a l'air bien et propre.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X