Estou lidando com um aplicativo que precisa ler mais de 10 arquivos CSV (de tipos diferentes) como entrada. Os dados são lidos em um contêiner – std::map
ou vector
.
Anteriormente, cada tipo tinha sua própria função de análise, e estou trabalhando para unificá-la em uma única função padronizada: economizar na manutenção futura do código e fornecer relatórios de erros uniformes para arquivos corrompidos.
Esta função lê cada linha, discerne se o tipo de contêiner tem o conceito de a key
(like map
) e usa emplace
para essas e emplace_back
para as outras (like vector
).
A única expectativa da classe de valor do contêiner é que seu construtor possa instanciar a partir de uma linha CSV. Qualquer exceção do construtor é um erro fatal - o nome do arquivo de entrada e o número da linha são relatados e o programa é encerrado:
try {
if constexpr (is_associative_container<Container>(NULL)) {
result->emplace(typename Container::key_type(
key, keylen), value);
} else {
result->emplace_back(value);
}
} catch (const std::exception &e) {
fprintf(stderr, "%s:%zd: %s\n", path, line, e.what());
goto failure;
}
Tudo isso funciona e estou feliz - cerca de 75% da análise de CSV agora é feita por esta função.
Agora estou enfrentando o quarto restante dos arquivos CSV, que são menos simples: porque certas linhas neles requerem tratamento especial e seu conteúdo não deve ser armazenado no contêiner.
Como o value_type
construtor do sinaliza para a função que a exceção que ela está lançando não deve ser considerada fatal? Uma maneira é escolher uma das exceções padrão ( std::bad_function_call
?) como sinal, mas isso significaria que a exceção escolhida não deve ocorrer inesperadamente - o que não é confiável...
Algo mais?
Uma edição de pergunta coincidiu com a redação desta resposta. A resposta original está abaixo.
Observe que no seu código atual você já faz uma distinção entre exceções herdadas de
std::exception
e aquelas que não herdam destd::exception
. Um bom estilo é herdar todas as exceções,std::exception
mas a realidade geralmente é diferente.Você poderia introduzir algum tipo especial de exceção a ser lançada:
Resposta antiga sobre especificações de exceção dinâmicas...
Conforme mencionado nos comentários, as especificações de exceção dinâmica foram removidas do C++ 17.
Antes do C++ 17, uma função que lançava uma exceção não listada na especificação de exceção fazia o seguinte (de cppreference ):
Não há saída a menos que você conheça alguma exceção que seria aceita pela especificação da exceção, mas em geral você não sabe disso. Não estou ciente de deduzir as exceções "permitidas" no código genérico. De qualquer forma, o recurso foi removido. E, em certo sentido, já era "fatal" lançar uma exceção não listada na especificação da exceção, não é algo que você precise fazer extra.
Se for normal que a linha não entre no contêiner, então esse não é um fluxo excepcional e você não deveria usar exceções. A função deve receber outro parâmetro:
Function<bool(RowData)> shouldInsertIntoContainer
Ok, com base na minha própria inclinação - e nas sugestões de @Eljay (comentário) e @ 463035818_is_not_an_ai (resposta aceita), modifiquei o código assim: