Имеется кусок кода:
class Base {
public:
Base(void) {}
virtual ~Base(void) throw() {}
};
class Derived : public Base {
public:
::std::string s;
};
int main(int, char**)
{
return 0;
}
При компиляции в GCC выдает интересную ошибку:
test.cpp:9: error: looser throw specifier for ‘virtual Derived::~Derived()’
test.cpp:6: error: overriding ‘virtual Base::~Base() throw ()’
Самое интересное, что если сделать Derived::s типа, например, int, то ошибка исчезнет.
В чем же дело?
Во втором случае компилятор генерирует автоматический деструктор с сигнатурой virtual Derived::~Derived() throw(), в первом — просто virtual Derived::~Derived(). Почему же так происходит? Как оказалось, всё просто (отвлекусь: вспомнил старый универский анекдот: стоит профессор у доски и говорит: "Как бы это доказать? Или это очевидно?" Через три часа возвращается уставший студент с толстой распечаткой и говорит: "Действительно очевидно."). На самом деле, при генерации деструктора по умолчанию компилятор рассматривает сигнатуры деструкторов всех статических (не в плане static, а в плане "не динамических") членов класса, и выбирает такую сигнатуру, которая является пересечением всех рассмотренных сигнатур. Дело в том, что деструктор ::std::basic_string не имеет спецификации throw(), и поэтому наиболее совместимым является генерация автоматического деструктора без спецификации throw(). Расчет здесь прост: если компилятор сгенерирует деструктор со спецификацией throw(), а деструктор ::std::basic_string бросит исключение, то это будет нарушением спецификации и, следовательно, будет очень плохо (вообще, на мой взгляд, кидаться исключениями в деструкторе — дурной тон).
Поэтому правильные деструкторы приходится в таких случаях прописывать руками… ![]()

Меня зовут Владимир, я программист-фрилансер, специализирующийся на Web-программировании и програмировании под Linux.
По совместительству занимаюсь администрированием LAMP/LNMP-серверов и техническим переводом.




