Gostaria que meu código C ++ parasse de executar se uma determinada condição fosse atendida, mas não sei como fazer isso. Portanto, a qualquer momento, se uma if
afirmação for verdadeira, encerre o código da seguinte maneira:
if (x==1)
{
kill code;
}
main()
retorno de uso, em funções, use um valor de retorno adequado ou lance uma exceção adequada. Não useexit()
!NDEBUG
definido,assert
provavelmente se tornará um não operacional, então você não deve confiar nele para mais do que detectar bugs.return
frommain()
é perfeitamente lógico. Ele define o código de saída relatado pelo programa para o sistema operacional, o que pode ser útil em muitos casos (se o seu programa puder ser usado como parte de um processo maior, por exemplo).exit()
considerado ruim? - SO 25141737 e Como encerrar um programa C ++? - SO 1116493 agora estão fechados como duplicados deste. O primeiro deles tem uma referência a 'Crash-Software' que pode valer uma olhada, apenas para estimular o seu pensamento sobre como escrever software robusto.Respostas:
Existem várias maneiras, mas primeiro você precisa entender por que a limpeza de objetos é importante e, portanto, o motivo
std::exit
é marginalizado entre os programadores de C ++.RAII e desbobinamento de pilha
O C ++ faz uso de um idioma chamado RAII , que em termos simples significa que os objetos devem executar a inicialização no construtor e a limpeza no destruidor. Por exemplo, a
std::ofstream
classe [pode] abrir o arquivo durante o construtor, o usuário realiza operações de saída e, finalmente, no final de seu ciclo de vida, geralmente determinado por seu escopo, é chamado o destruidor que essencialmente fecha o arquivo e libera qualquer conteúdo escrito no disco.O que acontece se você não chegar ao destruidor para liberar e fechar o arquivo? Quem sabe! Mas, possivelmente, ele não gravará todos os dados que deveria gravar no arquivo.
Por exemplo, considere este código
O que acontece em cada possibilidade é:
os
, chamando seu destruidor e fazendo a limpeza adequada, fechando e liberando o arquivo para o disco.inner_mad
, o desbobinador passará pela pilhamad
emain
realizará a limpeza adequada, todos os objetos serão destruídos corretamente, incluindoptr
eos
.exit
é uma função C e não está ciente nem é compatível com os idiomas C ++. Ele não executa a limpeza em seus objetos, inclusiveos
no mesmo escopo. Portanto, seu arquivo não será fechado corretamente e, por esse motivo, o conteúdo poderá nunca ser gravado nele!return 0
e, portanto, tendo o mesmo efeito que a possibilidade 1, ou seja, limpeza adequada.Mas não tenha tanta certeza do que acabei de lhe contar (principalmente as possibilidades 2 e 3); continue lendo e descobriremos como executar uma limpeza adequada baseada em exceções.
Possíveis maneiras de terminar
Retorno do main!
Você deve fazer isso sempre que possível; sempre prefere retornar do seu programa retornando um status de saída adequado da main.
O chamador do seu programa e, possivelmente, o sistema operacional, pode querer saber se o que seu programa deveria fazer foi feito com êxito ou não. Por esse mesmo motivo, você deve retornar zero ou
EXIT_SUCCESS
sinalizar que o programa foi finalizado com êxito eEXIT_FAILURE
sinalizar que o programa foi finalizado sem êxito, qualquer outra forma de valor de retorno é definida pela implementação ( §18.5 / 8 ).No entanto, você pode estar muito envolvido na pilha de chamadas e retornar tudo isso pode ser doloroso ...
[Não] lance uma exceção
Lançar uma exceção executará a limpeza adequada do objeto usando o desenrolamento da pilha, chamando o destruidor de cada objeto em qualquer escopo anterior.
Mas aqui está o problema ! É definido pela implementação se o desenrolamento da pilha é executado quando uma exceção lançada não é tratada (pela cláusula catch (...)) ou mesmo se você tem uma
noexcept
função no meio da pilha de chamadas. Isto é afirmado em §15.5.1 [exceto.terminar] :Então nós temos que pegá-lo!
Lance uma exceção e pegue-a na principal!
Como as exceções não capturadas podem não executar o desenrolamento da pilha (e consequentemente não executam a limpeza adequada) , devemos capturar a exceção no main e retornar um status de saída (
EXIT_SUCCESS
ouEXIT_FAILURE
).Portanto, uma configuração possivelmente boa seria:
[Não] std :: exit
Isso não realiza nenhum tipo de desenrolamento da pilha, e nenhum objeto ativo na pilha chama seu respectivo destruidor para executar a limpeza.
Isso é imposto em §3.6.1 / 4 [basic.start.init] :
Pense nisso agora, por que você faria uma coisa dessas? Quantos objetos você danificou dolorosamente?
Outras alternativas [tão ruins]
Existem outras maneiras de encerrar um programa (além de travar) , mas elas não são recomendadas. Apenas para fins de esclarecimento, eles serão apresentados aqui. Observe como o término normal do programa não significa o desenrolamento da pilha, mas um estado aceitável para o sistema operacional.
std::_Exit
causa um encerramento normal do programa, e é isso.std::quick_exit
causa uma finalização normal do programa e chama osstd::at_quick_exit
manipuladores, nenhuma outra limpeza é executada.std::exit
causa um encerramento normal do programa e chama osstd::atexit
manipuladores. Outros tipos de limpeza são executados, como chamar destruidores de objetos estáticos.std::abort
causar um encerramento anormal do programa, nenhuma limpeza será realizada. Isso deve ser chamado se o programa for finalizado de uma maneira realmente inesperada. Ele não fará nada além de sinalizar o SO sobre o término anormal. Alguns sistemas executam um dump principal nesse caso.std::terminate
chama ostd::terminate_handler
que chamastd::abort
por padrão.fonte
new
lancesstd::bad_alloc
e seu programa esqueceu de capturar essa exceção em qualquer lugar) não desenrolará adequadamente a pilha antes de terminar. Isso parece bobo para mim: ela teria sido fácil, essencialmente envolver a chamada paramain
um trivialtry{
-}catch(...){}
bloco que garantiria pilha desenrolamento é feito corretamente, em tais casos, sem nenhum custo (por que eu quero dizer: programas não usar este não pagará pena). Existe alguma razão específica para isso não ser feito?std::abort
para que o sistema operacional possa liberar toda a memória, soquetes e descritores de arquivos sem trocar por um minuto.Como Martin York mencionou, a saída não realiza a limpeza necessária, como o retorno.
É sempre melhor usar o retorno no local de saída. Caso você não esteja no main, onde quer que você saia do programa, volte ao main primeiro.
Considere o exemplo abaixo. Com o programa a seguir, um arquivo será criado com o conteúdo mencionado. Mas se o retorno for comentado e a saída não comentada (0), o compilador não garante que o arquivo terá o texto necessário.
Não é só isso, ter vários pontos de saída em um programa tornará a depuração mais difícil. Use exit somente quando isso puder ser justificado.
fonte
return (EXIT_SUCCESS);
vezreturn(0)
Chame a
std::exit
funçãofonte
exit()
quando o código da sua biblioteca estiver sendo executado dentro do meu processo host - o último sairá no meio do nada.As pessoas estão dizendo "saída de chamada (código de retorno)", mas esta é uma forma incorreta. Em programas pequenos, tudo bem, mas há vários problemas com isso:
Realmente, a única vez que você deve sair do problema é com esta linha em main.cpp:
Se você estiver usando exit () para lidar com erros, deve aprender sobre exceções (e exceções de aninhamento), como um método muito mais elegante e seguro.
fonte
return 0;
coloque isso onde quiserint main()
e o programa será fechado imediatamente.fonte
main
.int main()
é diferente. O programa usaint main()
para começar e terminar. Não há outra maneira de fazer isso. O programa será executado até você retornar verdadeiro ou falso. Na maioria das vezes, você retornará 1 ou true, para indicar que o programa foi fechado corretamente (por exemplo: pode usar false se você não conseguir liberar memória ou qualquer outro motivo.) Deixar o programa ser executado é sempre uma má idéia, por exemplo:int main() { int x = 2; int foo = x*5; std::cout << "blah"; }
int main
; no entanto, nem sempre é uma boa ideia ter várias instruções de retorno em uma rotina principal. Uma ressalva em potencial é melhorar a legibilidade do código; no entanto, usar algo como um sinalizador booleano que altera o estado para impedir que determinadas seções de código sejam executadas nesse estado do aplicativo. Pessoalmente, acho que uma declaração de retorno comum torna a maioria dos aplicativos mais legíveis. Por fim, perguntas sobre limpeza de memória e fechamento de objetos de E / S corretamente antes da saída.true
a partirmain
para indicar uma terminação correta. Você deve retornar zero ouEXIT_SUCCESS
(ou, se desejarfalse
, que seria implicitamente convertido em zero) para indicar finalização normal. Para indicar falha, você pode retornarEXIT_FAILURE
. Qualquer outro significado de código é definido pela implementação (em sistemas POSIX, isso significa código de erro real).O programa será encerrado quando o fluxo de execução atingir o final da função principal.
Para finalizá-lo antes disso, você pode usar a função exit (int status), em que status é um valor retornado para o que iniciou o programa. 0 normalmente indica um estado sem erro
fonte
Retorne um valor seu
main
ou use aexit
função Ambos assumem um int. Realmente não importa qual valor você devolve, a menos que tenha um processo externo observando o valor de retorno.fonte
Se houver um erro em algum lugar profundo do código, lance uma exceção ou defina o código de erro. É sempre melhor lançar uma exceção em vez de definir códigos de erro.
fonte
Geralmente você usaria o
exit()
método com um status de saída apropriado .Zero significaria uma corrida bem-sucedida. Um status diferente de zero indica que ocorreu algum tipo de problema. Esse código de saída é usado pelos processos pai (por exemplo, scripts de shell) para determinar se um processo foi executado com êxito.
fonte
return 0;
. Eu suponho queexit()
é comoassert(false);
e, portanto, deve ser usado apenas no desenvolvimento para detectar problemas precocemente.Além de chamar exit (error_code) - que chama manipuladores atexit, mas não destruidores de RAII etc. -, cada vez mais eu uso exceções.
Cada vez mais meu programa principal se parece
onde primary_main em onde todas as coisas originalmente foram colocadas - ou seja, o main original é renomeado como secundário_main e o stub main acima é adicionado. Isso é apenas um detalhe, para que não haja muito código entre a bandeja e a captura principal.
Se desejar, pegue outros tipos de exceção.
Eu gosto bastante de capturar tipos de erro de string, como std :: string ou char *, e imprimir aqueles no manipulador de captura principal.
Usar exceções como essa pelo menos permite que os destruidores de RAII sejam chamados, para que eles possam fazer a limpeza. O que pode ser agradável e útil.
No geral, o tratamento de erros em C - saída e sinais - e o tratamento de erros em C ++ - exceções de tentar / capturar / lançar - são executados juntos na melhor das hipóteses.
Então, onde você detecta um erro
ou algum tipo de exceção mais específico.
fonte
exit
seu programa. Desde que você estámain
, você pode apenasreturn exitCode;
.Se a sua declaração if estiver em loop, você pode usar
Se você deseja escapar de algum código e continuar em loop, use:
continuar;
Se sua instrução if não estiver em Loop, você pode usar:
fonte
A
exit()
função Cara ... é definida em stdlib.hEntão você precisa adicionar um pré-processador.
Coloque
include stdlib.h
na seção de cabeçalhoEm seguida, use
exit();
onde quiser, mas lembre-se de colocar um número intermediário entre parênteses de saída.por exemplo:
fonte
Se a condição que estou testando for realmente uma má notícia, eu faço o seguinte:
Isso me dá um bom coredump de onde posso examinar a situação.
fonte
Para quebrar uma condição, use o retorno (0);
Então, no seu caso, seria:
fonte