Este é um exemplo do que costumo fazer quando desejo adicionar algumas informações a uma exceção:
std::stringstream errMsg;
errMsg << "Could not load config file '" << configfile << "'";
throw std::exception(errMsg.str().c_str());
Existe uma maneira melhor de fazer isso?
std∷exception
não tem um construtor comchar*
arg.std::string
tem um construtor implícito que leva umconst char*
...std::exception
classes filhas de , e é usado por suas versões destd::runtime_error
estd::logic_error
. Além dos definidos pelo padrão, a versão do MSVS de<exception>
também inclui mais dois construtores, um pegando(const char * const &)
e outro pegando(const char * const &, int)
. Eles são usados para definir uma variável privadaconst char * _Mywhat
,; se_Mywhat != nullptr
, então owhat()
padrão é retorná-lo. O código que depende dele provavelmente não é portátil.Respostas:
Aqui está minha solução:
Exemplo:
fonte
As exceções padrão podem ser construídas a partir de
std::string
:Observe que a classe base não
std::exception
pode ser construída dessa forma; você tem que usar uma das classes derivadas concretas.fonte
Existem diferentes exceções, como
runtime_error
,range_error
,overflow_error
,logic_error
, etc .. Você precisa passar a corda em seu construtor, e você pode concatenar o que quiser à sua mensagem. Isso é apenas uma operação de string.Você também pode usar
boost::format
desta forma:fonte
A seguinte classe pode ser muito útil:
Exemplo de uso:
fonte
throw std::runtime_error(sprintf("Could not load config file '%s'", configfile.c_str()))
throw std::runtime_error("Could not load config file " + configfile);
(convertendo um ou outro argumento para,std::string
se necessário).printf
e amigos são iminentes no C ++ 11. O buffer de tamanho fixo é uma bênção e uma maldição: ele não falha em situações de poucos recursos, mas pode truncar a mensagem. Considero truncar uma mensagem de erro uma opção melhor do que falhar. Além disso, a conveniência das strings de formato foi comprovada por muitas linguagens diferentes. Mas você está certo, é em grande parte uma questão de gosto.Use o operador literal de string se C ++ 14 (
operator ""s
)ou defina seu próprio se estiver em C ++ 11. Por exemplo
Sua declaração de lançamento ficará assim
que parece bom e limpo.
fonte
Uma maneira realmente melhor seria criar uma classe (ou classes) para as exceções.
Algo como:
O motivo é que as exceções são muito mais preferíveis do que apenas transferir uma string. Fornecendo classes diferentes para os erros, você dá aos desenvolvedores a chance de lidar com um erro específico de uma forma correspondente (não apenas exibir uma mensagem de erro). As pessoas que detectam sua exceção podem ser tão específicas quanto precisam se você usar uma hierarquia.
a) Pode ser necessário saber o motivo específico
a) outro não quer saber detalhes
Você pode encontrar inspiração neste tópico no https://books.google.ru/books?id=6tjfmnKhT24C Capítulo 9
Além disso, você pode fornecer uma mensagem personalizada também, mas tenha cuidado - não é seguro para compor uma mensagem com qualquer um
std::string
oustd::stringstream
ou qualquer outra forma que pode causar uma exceção .Geralmente, não há diferença se você aloca memória (trabalha com strings no modo C ++) no construtor da exceção ou imediatamente antes de lançar - a
std::bad_alloc
exceção pode ser lançada antes daquela que você realmente deseja.Portanto, um buffer alocado na pilha (como na resposta de Maxim) é uma maneira mais segura.
É muito bem explicado em http://www.boost.org/community/error_handling.html
Então, a maneira mais legal seria um tipo específico de exceção e evitar a composição da string formatada (pelo menos ao lançar).
fonte
Tive um problema semelhante, pois a criação de mensagens de erro personalizadas para minhas exceções personalizadas tornava o código feio. Esta foi a minha solução:
Isso separa a lógica para criar as mensagens. Eu tinha pensado originalmente em substituir what (), mas então você tem que capturar sua mensagem em algum lugar. std :: runtime_error já tem um buffer interno.
fonte
Talvez isto?
Ele cria um ostringstream temporário, chama os operadores << conforme necessário e então você envolve isso entre colchetes e chama a função .str () no resultado avaliado (que é um ostringstream) para passar uma std :: string temporária para o construtor de runtime_error.
Observação: o ostringstream e a string são temporários com valor r e, portanto, saem do escopo após o término desta linha. O construtor do seu objeto de exceção DEVE receber a string de entrada usando cópia ou (melhor) semântica de movimentação.
Adicional: não considero necessariamente essa abordagem como "prática recomendada", mas ela funciona e pode ser usada em uma pitada. Um dos maiores problemas é que esse método requer alocações de heap e, portanto, o operador << pode lançar. Você provavelmente não quer que isso aconteça; no entanto, se você entrar nesse estado, provavelmente terá muito mais problemas com que se preocupar!
fonte