У меня есть простой объект C++, который я создаю в начале функции F() для обеспечения вызова двух согласованных функций (OpDo, OpUndo) в начале и в конце F() , используя конструктор объекта и деструктор. Тем не менее, я не хочу, чтобы операция была отменена, если исключение было выбрано внутри тела F(). Можно ли это сделать чисто? Я прочитал около std :: uncaught-exception, но его использование, похоже, не рекомендуется.Как обнаружить разматывание стека в деструкторе
ответ
Большинство людей использовали std::uncaught_exception()
, чтобы попытаться рассказать, ожидает ли исключение, поэтому они могут генерировать исключение из деструктора, если его еще нет. Это обычно считается не хорошей идеей.
Если вы хотите не отменить операцию, если возникло исключение, она должна сделать трюк.
Помните, что деструктор - это ваш последний шанс освободить любые ресурсы, которые имеет объект, потому что после завершения деструктора объект не существует и все оставшиеся ресурсы теперь просочились. Если OpDo()
выделяет любые файлы памяти или файлов или что-то еще, вам нужно иметь дело с этим в деструкторе, независимо от того, что.
Давайте предположим, что ваш F возвращает некоторый класс Helper:
Helper F()
{
MyClass doUndoWrapper;
}
Когда поток нормально - Helper создается. Когда возникает исключение, копия Helper не создается. Попробуйте использовать эту семантику, поместив ее в частный конструктор области Helper и объявив F как друга - так что никто не мог создать помощника.
Что? Это не совсем четкий ответ. –
@C Johnson - Если вы используете «Помощник» в качестве возвращаемого значения, вы получаете следующие преимущества (1) Помощник создается в начале по мере необходимости (поэтому поместите OpDo в конструктор) (2) Вы можете узнать, успешно ли функция F вернулась - вызванный конструктор копирования (так что место OpUndo там) (3) в случае исключения не вызвал конструктор копирования. Чтобы прояснить это, я меняю код, чтобы отразить эту идею. – Dewfy
Вы можете подобрать Scope Guard idiom. Вместо того, чтобы не делать что-то в деструкторе, если исключение не брошено, мы инвертировать, что и только сделать что-то, если исключение не брошено:
class DoUndoRAII{
public:
DoUndoRAII()
: noexcept_(false)
{
// your stuff here
}
~DoUndoRAII(){
if(noexcept_){
// do whatever you need to do
}
}
void no_exception(){
noexcept_ = true;
}
private:
bool noexcept_;
};
void func(){
DoUndoRAII do_undo;
// last line
do_undo.no_exception();
}
Когда исключение, do_undo.no_exception()
никогда не будет называться и поэтому никогда не устанавливайте значение noexcept_
в значение true. :) Пример можно найти here on Ideone.
- 1. переполнения стека в деструкторе C++
- 2. Как обнаружить объекты стека, падающие
- 3. Разматывание Segue приложением?
- 4. Разматывание подкласса UIStoryboardSegue в UINavigationController
- 5. Как сделать разматывание SEGUE в Xcode
- 6. Обнаружить границы стека текущей нити
- 7. GCC, как обнаружить переполнение буфера стека
- 8. Try Поймайте блок в деструкторе
- 9. Ошибка сегментации в деструкторе
- 10. Multiple удалить в деструкторе
- 11. Использование HttpClient в деструкторе
- 12. Как сделать = удалить на деструкторе препятствует распределению?
- 13. Удаление указателей в деструкторе
- 14. Weird перечисления в деструкторе
- 15. Исключение в деструкторе
- 16. Ошибка в деструкторе DAG
- 17. Ошибка QVariantMap в деструкторе
- 18. Регистрация в деструкторе
- 19. ошибка в классе деструкторе
- 20. PDI: Одновременное разматывание двух массивов от MongoDB
- 21. Определение segue и разматывание идентификаторов VC?
- 22. Переполнение буфера стека (Windows, C++): как я могу обнаружить преступника?
- 23. Завершить текущий поток в деструкторе
- 24. Как безопасно удалить указатель потока в деструкторе?
- 25. Как удалить указатель void в деструкторе?
- 26. Модальное разматывание не работает с яблочным MutlipleDetailViews
- 27. Удаление массива в деструкторе класса
- 28. ошибка шины GMock в деструкторе
- 29. Обработка исключений в виртуальном деструкторе
- 30. Выполнение нового процесса в деструкторе
Использование'uncaught_exception 'может быть в порядке, но это зависит от того, что вы делаете (и, следовательно, субъективно ..). Тем не менее, не могли бы вы подробнее рассказать о операции do/undo и об исключении (-ях)? – Macke
Если вы не хотите, чтобы какое-либо действие произошло, когда исключение распространялось, тогда просто не используйте RAII. Просто поставьте OpDo() и OpUndo() прямо в код. –
«его использование, по-видимому, не рекомендуется», поскольку оно не работает как средство обнаружения того, что бит стека, содержащий ваш объект, разматывается из-за исключения или из-за нормального возврата. Предположим, что кто-то помещает некоторый код в деструктор, который вызывает вашу функцию F. Предположим далее, что такой объект уничтожается как часть раскрутки стека во время исключения. Тогда 'uncaught_exception' вернет' true', но исключение не было выбрано внутри тела F(). –