Вопрос 1: Как этого добиться, ведь даже если мы сами не кидаем исключение, его может кинуть какой-то метод/функция/оператор, который мы зовем в деструкторе?
Вопрос 2: В книге "Решение сложных задач на С++" Герб Саттер отмечает, что неплохо бы все деструкторы писать так ~SomeClass() throw(). Но я редко вижу такое объявление деструкторов в проектах. Так все таки нужно или нет писать деструкторы со спецификацией throw()?
Здравствуйте, Максим Рогожин, Вы писали:
МР>Деструкторы не должны кидать исключения.
МР>Вопрос 1: Как этого добиться, ведь даже если мы сами не кидаем исключение, его может кинуть какой-то метод/функция/оператор, который мы зовем в деструкторе?
Видимо не вызывать того, что может кинуть исключение.
Либо, если не обойтись, то оборачивать в try/catch.
МР>Вопрос 2: В книге "Решение сложных задач на С++" Герб Саттер отмечает, что неплохо бы все деструкторы писать так ~SomeClass() throw(). Но я редко вижу такое объявление деструкторов в проектах. Так все таки нужно или нет писать деструкторы со спецификацией throw()?
throw() считается deprecated. Так что этот совет можно проигнорировать.
Читать про noexcept.
_____________________
С уважением,
Stanislav V. Zudin
Деструкторы по умолчанию noexcept, так что бросать вообще из них нельзя, ну или писать явно noexcept(false) если с этим жить.
МР>Вопрос 1: Как этого добиться, ведь даже если мы сами не кидаем исключение, его может кинуть какой-то метод/функция/оператор, который мы зовем в деструкторе?
Не делать ничего в деструкторах.
МР>Вопрос 2: В книге "Решение сложных задач на С++" Герб Саттер отмечает, что неплохо бы все деструкторы писать так ~SomeClass() throw(). Но я редко вижу такое объявление деструкторов в проектах. Так все таки нужно или нет писать деструкторы со спецификацией throw()?
throw() уже deprecated, да, его никто не писал, и не нужно начинать.
Здравствуйте, Максим Рогожин, Вы писали:
МР>Вопрос 1: Как этого добиться, ведь даже если мы сами не кидаем исключение, его может кинуть какой-то метод/функция/оператор, который мы зовем в деструкторе?
МР>>Вопрос 1: Как этого добиться, ведь даже если мы сами не кидаем исключение, его может кинуть какой-то метод/функция/оператор, который мы зовем в деструкторе? AG>Не делать ничего в деструкторах.
Ну вот надо например в деструкторе позвать closeDataBaseConnection(), а этот метод исключение кидать может. Как делать?
Здравствуйте, Pzz, Вы писали:
Pzz>Здравствуйте, Максим Рогожин, Вы писали:
МР>>Вопрос 1: Как этого добиться, ведь даже если мы сами не кидаем исключение, его может кинуть какой-то метод/функция/оператор, который мы зовем в деструкторе?
Pzz>Ловить и обрабатывать локально.
Если в деструкторе несколько разных функций вызывается, которые в свою очередь другие функции зовут, да еще учесть, что со временем реализация этих функций может измениться (сейчас не бросают исключение, но в будущем могут бросать), то получается, что надо сразу весь код деструктора брать в блок try-catch?
~SomeClass() {
try {
// здесь код деструктора
} catch(...) {
// например, выводим сообщение в лог-файл?
}
}
Здравствуйте, Максим Рогожин, Вы писали:
МР>Если в деструкторе несколько разных функций вызывается, которые в свою очередь другие функции зовут, да еще учесть, что со временем реализация этих функций может измениться (сейчас не бросают исключение, но в будущем могут бросать), то получается, что надо сразу весь код деструктора брать в блок try-catch?
А объект после пойманного и отправленного в лог исключения будет "разобран"? Не получится так, что останутся неосвобожденные ресурсы, до освобождения которых просто не дошло дело?
Здравствуйте, Pzz, Вы писали:
Pzz>А объект после пойманного и отправленного в лог исключения будет "разобран"? Не получится так, что останутся неосвобожденные ресурсы, до освобождения которых просто не дошло дело?
Кстати, да, получится!) Так я вот и спрашиваю что делать с исключениями в деструкторах)
Здравствуйте, Максим Рогожин, Вы писали:
Pzz>>А объект после пойманного и отправленного в лог исключения будет "разобран"? Не получится так, что останутся неосвобожденные ресурсы, до освобождения которых просто не дошло дело?
МР>Кстати, да, получится!) Так я вот и спрашиваю что делать с исключениями в деструкторах)
Ловить и обрабатывать локально. Не прятать, кокетливо обернув в лог, который никто не читает, а обрабатывать по существу
Здравствуйте, Максим Рогожин, Вы писали:
МР>Привет!
МР>Деструкторы не должны кидать исключения.
МР>Вопрос 1: Как этого добиться, ведь даже если мы сами не кидаем исключение, его может кинуть какой-то метод/функция/оператор, который мы зовем в деструкторе?
Можно проверять каждое выражение на noexcept, если хочется хардкора.
Типа
static_assert(noexcept(c=a+b),"should be noexcept);
c=a+b;
Но это хардкор и не всегда имеет смысл — ведь ты заранее можешь знать, что некоторые вызовы не сгенерируют исключений, даже если они и не объявлены noexcept — просто потому что ты уверен в состоянии и аргументах.
Например, если ты проверил индекс, что он точно не вылетит за пределы вектора, то вызов vector::at точно не сгенерирует исключения, несмотря на то, что в других случаях он может и поэтому, естественно, не объявлен noexcept.
МР>Вопрос 2: В книге "Решение сложных задач на С++" Герб Саттер отмечает, что неплохо бы все деструкторы писать так ~SomeClass() throw(). Но я редко вижу такое объявление деструкторов в проектах. Так все таки нужно или нет писать деструкторы со спецификацией throw()?
Книга Саттера — про С++98.
Начиная с С++11 все деструкторы noexcept по умолчанию. Т.е. если ты собираешься что-то бросать из деструктора, ты явно должен объявить его с noexcept(false), в противном случае ничего делать не надо.
Здравствуйте, Максим Рогожин, Вы писали:
МР>Ну вот надо например в деструкторе позвать closeDataBaseConnection(), а этот метод исключение кидать может. Как делать?
Максим Рогожин:
МР>Ну вот надо например в деструкторе позвать closeDataBaseConnection(), а этот метод исключение кидать может. Как делать?
Зависит от соглашений по обработке исключений в конкретно взятом проекте. Некоторые соглашения могут подразумевать, что всякая функция, освобождающая ресурс, обязана быть noexcept, и тогда бросающего closeDataBaseConnection в программе не должно существовать в принципе. Если же closeDataBaseConnection — это часть чужой либы, то тут возможны два случая:
1) если closeDataBaseConnection не умеет гарантированно чистить все локальные ресурсы соединения (на стороне, вызвавшей closeDataBaseConnection), то либа отправляется на помойку и заменяется более кошерной;
2) если closeDataBaseConnection гарантированно чистит все локальные ресурсы соединения, но может сообщать о каких-то проблемах путём бросания исключений, то closeDataBaseConnection оборачивается в noexcept функцию, в которую опционально может передаваться callback обработчик ошибок (опять же небросающий).
Здравствуйте, Максим Рогожин, Вы писали:
МР>Здравствуйте, jazzer, Вы писали:
J>>Книга Саттера — про С++98.
МР>А есть ли более современные книги для углубленного изучения базового С++ ?
Здравствуйте, jazzer, Вы писали:
МР>>А есть ли более современные книги для углубленного изучения базового С++ ?
J>Есть Effective Modern C++ Майерса (вот по-русски: https://www.ozon.ru/context/detail/id/34747131/)
Я посмотрел содержание — эта книга по новым фичам C++, а мне нужны базовые, которые описываются, например, в "Effective C++" Мейерса — но только эта книга тоже выпущена лет 15 назад. Стоит читать ее сейчас или она уже устарела?
вы можете изучить весь английский алфавит, даже выучить много слов, но толку от этого будет мало
в любом деле важен опыт
вы ядро линукса читаете легко ?
а в куте можете быстро разобраться ?
итд
тогда можете хоть все книги мира по С++ перечитать, толку не будет
Здравствуйте, jazzer, Вы писали:
МР>>Вопрос 2: В книге "Решение сложных задач на С++" Герб Саттер отмечает, что неплохо бы все деструкторы писать так ~SomeClass() throw(). Но я редко вижу такое объявление деструкторов в проектах. Так все таки нужно или нет писать деструкторы со спецификацией throw()?
J>Книга Саттера — про С++98. J>Начиная с С++11 все деструкторы noexcept по умолчанию. Т.е. если ты собираешься что-то бросать из деструктора, ты явно должен объявить его с noexcept(false), в противном случае ничего делать не надо.
Это не совсем так. Если у класса есть член и/или базовый класс, деструктор которого явно помечен noexcept(false), то неявная пометка noexcept(true) с деструктора такого класса снимается:
Разумеется, если деструктору класса Foo добавить явный спецификатор noexcept/noexcept(true), то будет вызван terminate_handler (и в том, и в другом случаях).
Поэтому, возможно, совет Саттера все еще актуален в какой-то степени (хотя вместо deprecated throw() [который приравнен к noexcept(true), начиная с C++17] сейчас, конечно, лучше писать noexcept или noexcept(true)), ему стоит следовать, чтобы избежать проблем при потенциальном рефакторинге (в ходе которого у класса могут появиться члены и/или базовые классы, деструктор которых помечен noexcept(false)).
Здравствуйте, Максим Рогожин, Вы писали:
МР>...в "Effective C++" Мейерса — но только эта книга тоже выпущена лет 15 назад. Стоит читать ее сейчас или она уже устарела?
Стоит, просто с поправками на современное состояние дел.
Поправок таких будет не очень много.
Основные отличия можно посмотреть в C++11FAQ Страуструпа.
Здравствуйте, Stanislav V. Zudin, Вы писали:
SVZ>Здравствуйте, Максим Рогожин, Вы писали:
МР>>Деструкторы не должны кидать исключения.
МР>>Вопрос 1: Как этого добиться, ведь даже если мы сами не кидаем исключение, его может кинуть какой-то метод/функция/оператор, который мы зовем в деструкторе?
SVZ>Видимо не вызывать того, что может кинуть исключение. SVZ>Либо, если не обойтись, то оборачивать в try/catch.
МР>>Вопрос 2: В книге "Решение сложных задач на С++" Герб Саттер отмечает, что неплохо бы все деструкторы писать так ~SomeClass() throw(). Но я редко вижу такое объявление деструкторов в проектах. Так все таки нужно или нет писать деструкторы со спецификацией throw()?
SVZ>throw() считается deprecated. Так что этот совет можно проигнорировать. SVZ>Читать про noexcept.
Мне если честно не очень понятно почему в 21 веке, когда наши космические корабли бороздят...,
у людей всё ещё возникают такие вопросы.
Можно ведь реализовать метод в котором будут находится все страшные и ужасные разбойники Бармалеи:
void
someclass::
destructor_realisator()
{
try{
//тут значит много разного
// проверки, освобождение занятых ресурсов,
// вспоминаем старую добрую идиому RAII
//
}
catch(...)
{
//чтото вроде log-файла пишем кстати есть ньюансы
1)код запросто может сам вызвать исключение
2)информативность подобного лога вызывает сомнения.
Но это не суть важно, ведь мы хитрые пацаны.
}
}
//поэтому:)
~someclass()
{
try
{
destructor_realisator();
}
catch(...)
{
}
}
Както так. я делал когда был студентом. Потом стал делать намного лучше, о это уже совсем другая история
Как давно я здесь небыл Родной rsdn
Если карта не соответствует местности доверяй местности