Я бы хотел, чтобы мой код на С++ прекратил работу, если выполнено определенное условие, но я не уверен, как это сделать. Поэтому в любой момент, если инструкция if
истинна, завершите код следующим образом:
if (x==1)
{
kill code;
}
Я бы хотел, чтобы мой код на С++ прекратил работу, если выполнено определенное условие, но я не уверен, как это сделать. Поэтому в любой момент, если инструкция if
истинна, завершите код следующим образом:
if (x==1)
{
kill code;
}
Существует несколько способов, но сначала вам нужно понять, почему важно очистить объект, и поэтому причина std::exit
является маргинальной среди С++ программисты.
С++ использует идиому под названием RAII, которая в простых терминах означает, что объекты должны выполнять инициализацию в конструкторе и очищать в деструкторе, Например, std::ofstream
класс [может] открыть файл во время конструктора, тогда пользователь выполняет на нем выходные операции и, наконец, в конце своего жизненного цикла, обычно определяемого его областью, деструктор называется тем, что существенно закрывает файл и сбрасывает любое записанное содержимое на диск.
Что произойдет, если вы не дойдете до деструктора, чтобы сбросить и закрыть файл? Кто знает! Но, возможно, он не будет записывать все данные, которые он должен был записать в файл.
Например, рассмотрим этот код
#include <fstream>
#include <exception>
#include <memory>
void inner_mad()
{
throw std::exception();
}
void mad()
{
std::unique_ptr<int> ptr(new int);
inner_mad();
}
int main()
{
std::ofstream os("file.txt");
os << "Content!!!";
int possibility = /* either 1, 2, 3 or 4 */;
if(possibility == 1)
return 0;
else if(possibility == 2)
throw std::exception();
else if(possibility == 3)
mad();
else if(possibility == 4)
exit(0);
}
Что происходит в каждой возможности:
os
, тем самым называя его деструктор и делая правильную очистку, закрывая и промывая файл до диск.inner_mad
, разматыватель будет проходить через стек mad
и main
для правильной очистки, все объекты будут разрушены должным образом, включая ptr
и os
.exit
является функцией C и не знает и не совместим с идиомами С++. Он не выполняет выполнять очистку ваших объектов, включая os
в той же области. Таким образом, ваш файл не будет закрыт должным образом, и по этой причине контент никогда не будет записан в него!return 0
и, таким образом, получив тот же эффект, что и возможность 1, т.е. правильная очистка.Но не будьте так уверенны в том, что я только что сказал вам (в основном возможности 2 и 3); продолжить чтение, и мы узнаем, как выполнить правильную очистку на основе исключений.
Вы должны делать это, когда это возможно; всегда предпочитают возвращаться из вашей программы, возвращая правильный статус выхода из основного.
Вызывающая ваша программа и, возможно, операционная система могут захотеть узнать, успешно ли выполнена ваша программа или нет. По этой же причине вы должны вернуть либо ноль, либо EXIT_SUCCESS
, чтобы сообщить, что программа успешно завершена, и EXIT_FAILURE
, чтобы сигнализировать о завершении неудачной программы, любая другая форма возвращаемого значения определяется реализацией (§18.5/8).
Однако вы можете быть очень глубоки в стеке вызовов и вернуть все это может быть больно...
Бросок исключений будет выполнять правильную очистку объекта с помощью разворачивания стека, вызывая деструктор каждого объекта в любой предыдущей области.
Но вот catch! Это реализация определяет, выполняется ли разматывание стека, когда исключение броска не обрабатывается (по предложению catch (...)) или даже если у вас есть noexcept
в середине стека вызовов. Об этом говорится в §15.5.1 [except.terminate]:
В некоторых ситуациях обработка исключений должна быть отменена для менее тонких методов обработки ошибок. [Примечание: Эти ситуации:
[...]
- , когда механизм обработки исключений не может найти обработчик для генерируемого исключения (15.3) или когда поиск обработчика (15.3) встречает самый внешний блок функции с
noexcept
-спецификацией, который не допускает исключения (15.4) или [...][...]
В таких случаях вызывается std:: terminate() (18.8.3). В ситуации, когда соответствующий обработчик не найден, он определяется реализацией независимо от того, разрывается ли стек до того, как std:: terminate() вызывается [...]
Итак, мы должны его поймать!
Так как неотображаемые исключения могут не выполнять разворачивание стека (и, следовательно, не будут выполнять надлежащую очистку), мы должны поймать исключение в основном, а затем вернуть статус выхода (EXIT_SUCCESS
или EXIT_FAILURE
).
Таким образом, возможно, хорошая настройка:
int main()
{
/* ... */
try
{
// Insert code that will return by throwing a exception.
}
catch(const std::exception&) // Consider using a custom exception type for intentional
{ // throws. A good idea might be a `return_exception`.
return EXIT_FAILURE;
}
/* ... */
}
Это не выполняет какой-либо раскрутки стека, и ни один живой объект в стеке не вызовет его соответствующий деструктор для выполнения очистки.
Это применяется в §3.6.1/4 [basic.start.init]:
Завершение работы программы без выхода из текущего блока (например, путем вызова функции std:: exit (int) (18.5)) не уничтожает объекты с автоматическим временем хранения (12.4). Если std:: exit вызывается для завершения программы во время уничтожения объекта со статикой или продолжительностью хранения потоков, программа имеет поведение undefined.
Подумайте об этом сейчас, зачем вам это делать? Сколько объектов вы пострадали от боли?
Существуют и другие способы прекращения программы (кроме сбоев), но они не рекомендуются. Только для разъяснения они будут представлены здесь. Обратите внимание, что нормальное завершение программы не означает сброс стека, но состояние в операционной системе.
std::_Exit
вызывает нормальное завершение программы и что оно.std::quick_exit
вызывает обычное завершение программы и вызывает std::at_quick_exit
, никакая другая очистка не выполняется.std::exit
вызывает нормальное завершение программы, а затем вызывает std::atexit
. Другие виды очистки выполняются, например, вызов деструкторов статических объектов.std::abort
вызывает ненормальное завершение программы, никакая очистка не выполняется. Это следует назвать, если программа завершилась действительно, действительно неожиданным образом. Он ничего не сделает, кроме как сигнализирует ОС об аномальном завершении. В этом случае некоторые системы выполняют сброс ядра.std::terminate
вызывает std::terminate_handler
, который звонит std::abort
по умолчанию.Как упоминал Мартин Йорк, выход не выполняет необходимую очистку, например, возврат.
Всегда лучше использовать возврат в месте выхода. Если вы не находитесь в основном, где бы вы хотели выйти из программы, сначала вернитесь к главному.
Рассмотрим приведенный ниже пример. В следующей программе будет создан файл с указанным контентом. Но если return комментируется и uncommented exit (0), компилятор не гарантирует, что файл будет иметь необходимый текст.
int main()
{
ofstream os("out.txt");
os << "Hello, Can you see me!\n";
return(0);
//exit(0);
}
Не только это. Наличие нескольких точек выхода в программе сделает отладку более сложной. Используйте exit только тогда, когда это может быть оправдано.
Вызвать функцию std::exit
.
Люди говорят "call exit (код возврата)", но это плохая форма. В небольших программах это нормально, но с этим связано несколько проблем:
Действительно, единственный раз, когда вы должны выйти из проблемы, это строка в main.cpp:
return 0;
Если вы используете exit() для обработки ошибок, вы должны узнать об исключениях (и исключениях вложенности), как более элегантный и безопасный метод.
return 0;
поместите это, где хотите, в int main()
, и программа немедленно закроется.
Верните значение из main
или используйте функцию exit
. Оба берут int. Неважно, какое значение вы вернете, если у вас нет внешнего процесса, смотрящего на возвращаемое значение.
Программа завершится, когда поток выполнения достигнет конца основной функции.
Чтобы прервать его до этого момента, вы можете использовать функцию exit (int status), где status - это значение, возвращаемое для запуска программы. 0 обычно указывает состояние без ошибок
Если у вас есть ошибка где-то глубоко в коде, то либо выбросите исключение, либо установите код ошибки. Всегда лучше создавать исключение вместо установки кодов ошибок.
Как правило, вы должны использовать метод exit()
с соответствующим статусом выхода.
Ноль будет означать успешное выполнение. Не нулевой статус указывает на какую-то проблему. Этот код выхода используется родительскими процессами (например, сценариями оболочки), чтобы определить, успешно ли выполняется процесс.
Помимо вызова exit (error_code) - который вызывает обработчики atexit, но не RAII-деструкторы и т.д. - все больше я использую исключения.
Все больше и больше моя основная программа выглядит как
int main(int argc, char** argv)
{
try {
exit( secondary_main(argc, argv );
}
catch(...) {
// optionally, print something like "unexpected or unknown exception caught by main"
exit(1);
}
}
где secondary_main в котором все вещи, которые изначально были поставлены, т.е. исходный основной объект переименован в secondary_main, и добавляется основной заглушка. Это всего лишь тонкость, так что между лотком и уловом не слишком много кода.
Если вы хотите, поймайте другие типы исключений.
Мне очень нравится захватывать строковые типы ошибок, например std::string или char *, и печатать эти
в обработчике уловов в основном.
Использование таких исключений, по крайней мере, позволяет вызвать деструкторы RAII, чтобы они могли выполнять очистку. Что может быть приятным и полезным.
В целом, обработка ошибок C - выход и сигналы - и обработка ошибок С++ - try/catch/throw exceptions - в лучшем случае играют вместе непоследовательно.
Затем, когда вы обнаруживаете ошибку
throw "error message"
или более конкретный тип исключения.
Чтобы разбить условие, используйте return (0);
Итак, в вашем случае это будет:
if(x==1)
{
return 0;
}
Если ваш оператор if находится в Loop Вы можете использовать
break;
Если вы хотите избежать некоторого кода и продолжить цикл Используйте:
продолжить
Если ваш оператор if не в Loop Вы можете использовать:
return 0;
Or
exit();
Функция dude... exit()
определена в stdlib.h
Итак, вам нужно добавить препроцессор.
Поместите include stdlib.h
в раздел заголовка
Затем используйте exit();
везде, где захотите, но не забудьте указать номер интергера в скобках выхода.
например:
exit(0);
Если условие, которое я тестирую, это действительно плохие новости, я делаю это:
*(int*) NULL= 0;
Это дает мне хороший coredump, откуда я могу проверить ситуацию.