Estou codificando uma pequena biblioteca e estou tendo problemas para projetar o tratamento de exceções. Devo dizer que estou (ainda) confuso com esse recurso da linguagem C ++ e tentei ler o máximo possível sobre o assunto para entender o que eu teria que fazer para trabalhar adequadamente com classes de exceção.
Decidi usar um system_error
tipo de abordagem inspirado na implementação do STL da future_error
classe.
Eu tenho uma enumeração que contém os códigos de erro:
enum class my_errc : int
{
error_x = 100,
error_z = 101,
error_y = 102
};
e uma única classe de exceção (suportada por um error_category
tipo de estruturas e tudo o mais necessário pelo system_error
modelo):
// error category implementation
class my_error_category_impl : public std::error_category
{
const char* name () const noexcept override
{
return "my_lib";
}
std::string message (int ec) const override
{
std::string msg;
switch (my_errc(ec))
{
case my_errc::error_x:
msg = "Failed 1.";
break;
case my_errc::error_z:
msg = "Failed 2.";
break;
case my_errc::error_y:
msg = "Failed 3.";
break;
default:
msg = "unknown.";
}
return msg;
}
std::error_condition default_error_condition (int ec) const noexcept override
{
return std::error_condition(ec, *this);
}
};
// unique instance of the error category
struct my_category
{
static const std::error_category& instance () noexcept
{
static my_error_category_impl category;
return category;
}
};
// overload for error code creation
inline std::error_code make_error_code (my_errc ec) noexcept
{
return std::error_code(static_cast<int>(ec), my_category::instance());
}
// overload for error condition creation
inline std::error_condition make_error_condition (my_errc ec) noexcept
{
return std::error_condition(static_cast<int>(ec), my_category::instance());
}
/**
* Exception type thrown by the lib.
*/
class my_error : public virtual std::runtime_error
{
public:
explicit my_error (my_errc ec) noexcept :
std::runtime_error("my_namespace ")
, internal_code(make_error_code(ec))
{ }
const char* what () const noexcept override
{
return internal_code.message().c_str();
}
std::error_code code () const noexcept
{
return internal_code;
}
private:
std::error_code internal_code;
};
// specialization for error code enumerations
// must be done in the std namespace
namespace std
{
template <>
struct is_error_code_enum<my_errc> : public true_type { };
}
Eu só tenho um pequeno número de situações nas quais eu lanço exceções ilustradas pela enumeração do código de erro.
O exposto acima não se encaixou bem com um dos meus revisores. Ele era da opinião de que eu deveria ter criado uma hierarquia de classes de exceção com uma classe base derivada std::runtime_error
porque ter o código de erro incorporado na condição mistura coisas - exceções e códigos de erro - e seria mais tedioso lidar com esse ponto. de manuseio; a hierarquia de exceções também permitiria fácil personalização da mensagem de erro.
Um dos meus argumentos era que eu queria simplificá-lo, que minha biblioteca não precisava lançar vários tipos de exceções e que a personalização também é fácil nesse caso, pois é tratada automaticamente - ela error_code
tem um error_category
associado que traduz o código para a mensagem de erro adequada.
Devo dizer que não defendi bem minha escolha, testemunho do fato de que ainda tenho alguns mal-entendidos sobre as exceções de C ++.
Gostaria de saber se meu design faz sentido. Quais seriam as vantagens do outro método sobre o que eu escolhi, pois tenho que admitir que não vejo isso também? O que eu poderia fazer para melhorar?