Деструктор, вызывающий функцию, которая может вызывать исключение в С++

Я знаю, что я не должен выдавать исключения из деструктора.

Если мой деструктор вызывает функцию, которая может генерировать исключение, нормально ли это, если я поймаю ее в деструкторе и не буду ее бросать? Или это может привести к прерыванию в любом случае, и я не должен вообще вызывать такие функции из деструктора?

Ответ 1

Да, это законно. Исключение не должно выходить из деструктора, но все, что происходит внутри деструктора или в его функциях, зависит от вас.

(Технически исключение может также выйти из вызова деструктора. Если это происходит во время разворачивания стека, потому что вызывается другое исключение, вызывается std::terminate. Поэтому он хорошо определен стандартом, но он очень плохой идея.)

Ответ 2

Да.

Посмотрите на класс std:: fstream в стандартной библиотеке для примера.

  • close() может потенциально вызвать исключение.
  • Деструктор может вызвать close(), но деструктор не выбрасывает (он будет проглатывать любые исключения).

Понятие состоит в том, что если деструктор вызывает любые методы, которые могут бросать, эти методы должны быть общедоступными. Таким образом, если пользователь вашего объекта хочет проверить исключения, он может использовать общедоступные методы и обрабатывать исключение. Если они не заботятся об исключении, просто дайте деструктору справиться с этой проблемой.

Возвращаясь к примеру std:: fstream.

{
    std::fstream   text("Plop");
    // Load Text.

    // I don't care if the close fails.
    // So let the destructor handle it and discard exceptions
}



{
    // If this fails to write I should at least warn the user.
    // So in this case I will explicitly try and close it.
    try
    {
        std::ofstram    password("/etc/password");
        // Update the password file.

        password.close();
    }
    catch(...)
    {
          Message.ShowDialog("You failed to update the Password File");
    }
}

Ответ 3

Здесь вы можете найти несколько примеров: https://software.intel.com/sites/products/documentation/doclib/iss/2013/sa-ptr/sa-ptr_win_lin/GUID-D2983B74-74E9-4868-90E0-D65A80F8F69F.htm

Если исключение оставляет деструктор во время стека, разматывая распространение другого исключения, вызывается std:: terminate().

Когда не выполняется разматывание стека, исключение может оставить деструктор без вызова std:: terminate(). Однако для объектов, выделенных в куче, это приведет к утечке памяти, потому что "оператор delete" не будет вызываться для объекта, который выдает исключение из своего деструктора. Удивительно, что деструктор базового класса по-прежнему вызывает в этом случае: Что происходит с деструктором базового класса, если деструктор производного класса генерирует исключение

Если исключение попадает внутрь деструктора (так, чтобы исключение не оставило деструктор), тогда проблема не возникает, даже если выполняется удаление стека другого исключения. Этот случай более подробно описан здесь: http://bin-login.name/ftp/pub/docs/programming_languages/cpp/cffective_cpp/MEC/MI11_FR.HTM

Ответ 4

Простой ответ, никогда не допускайте исключения из dtor!

Сложный ответ. Вы получаете только гвозди, если исключение выходит из dtor, тогда как другое исключение активно. Обычный случай для этого - это когда вы уже раскручиваете стек из другого исключения, и этот объект уничтожается. В этом случае, если исключение выходит из dtor, вызывается std::terminate, обратите внимание, что вы можете поместить свой собственный обработчик для std::terminate, вызвав std::set_terminate. Реализация по умолчанию std::terminate - это вызов abort.

Чтобы усложнить ситуацию, большинство функций, которые хотят сделать какие-либо гарантии об их безопасности исключений, в основном основной гарантии или сильной гарантии, полагаются на основные типы сами по себе, не бросают их dtor *

Реальный вопрос: какое состояние будет в вашей программе при возникновении этой ошибки? Как вы можете выздороветь? Где это должно быть обработано? Вам нужно посмотреть на ваш конкретный случай и решить эти проблемы. Иногда это просто прекрасно, чтобы поймать исключение и игнорировать его. В других случаях вам нужно поднять некоторые красные флаги.

Итак, ответ: это разрешено С++ вызывать исключение в dtor, но вы никогда не должны позволять ему убежать.

* Здесь краткое описание исключения исключений (здесь намного больше статья)

  • Резюме: Кратко определите гарантии безопасности исключений Abrahams (базовые, сильный, и nothrow).

Основная гарантия заключается в том, что не удалось операции могут изменять состояние программы, но никаких утечек не происходит и объекты/модули по-прежнему разрушаются и может использоваться в последовательном (но не обязательно предсказуемое).

Сильная гарантия включает транзакционная фиксация/откат семантика: гарантия неудачных операций состояние программы не изменяется с в отношении объектов, оперированных. Это означает отсутствие побочных эффектов, которые влияют объекты, включая действительность или содержимое связанных вспомогательных объектов таких как итераторы, указывающие на контейнеры манипулируют.

Незначительная гарантия означает, что неудачных операций не произойдет. операция не будет генерировать исключение.

Ответ 5

Вы можете найти эту страницу из С++ FAQ Lite, чтобы быть информативным. Основной ответ: "Не делай этого". Где именно вы планируете поймать это исключение? Независимо от того, что вы планируете делать, когда вы поймаете это исключение, просто сделайте это вместо вызова функции или чего-нибудь (например, запишите его или установите флаг, чтобы предупредить пользователя или что-то еще). Выбрасывание исключений из деструктора может привести к завершению работы всей программы.