Какова спецификация исключения для дефолтного виртуального деструктора в C++11?
Предположим, у меня есть:
class Foo
{
public:
virtual ~Foo()=default;
};
Что такое спецификация исключения для дефолтного деструктора? Является ли дефолтный деструктор эквивалентным:
virtual ~Foo() {};
or
virtual ~Foo() throw() {};
or
virtual ~Foo() noexcept {};
Раздел 15.4 стандарта C++11 говорит, что это зависит от спецификаций исключений функций, непосредственно вызываемых неявным определением деструктора. В этом случае нет ни членов, ни базовых классов, поэтому в AFAIK нет функций, напрямую вызываемых неявным деструктором. Это двусмысленность (или упущение) в стандарте?
Это имеет значение, конечно, потому что, если он неявно имеет throw(), тогда все подклассы должны объявить свои деструкторы с помощью throw(). Не говорите мне, что создавать деструкторы - это плохая идея, я это знаю. Я имею дело с большим количеством устаревшего кода, где спецификации исключений не использовались вообще.
В качестве информации, когда я пытался:
class SubFoo : public Foo
{
public:
virtual ~SubFoo();
};
Я получил ошибку (несоответствующие спецификации исключений) в GCC 4.4 (хотя я признаю, что у меня, возможно, не было правильных ключей командной строки), но не в XCode 4.3 с использованием компиляторов "11".
2 ответа
Вернитесь к предыдущему в том же предложении (§15.4 / 14):
... его неявная спецификация исключений определяет идентификатор типа T в том и только в том случае, если T разрешен спецификацией исключений функции, непосредственно вызванной неявным определением f;... "
Следовательно, если ~Foo
не вызывает никаких функций, у него есть неявное объявление, которое не позволяет создавать исключения.
Согласно §15.4/3:
Две спецификации исключений совместимы, если:
- оба не являются бросающими (см. ниже), независимо от их формы,
Это тот случай, поэтому не имеет значения, является ли объявление throw()
или же noexcept
- оба совместимы в любом случае.
Стандарт хорошо начинается в C++ 11 §8.4.2 / 2,
Если функция явно по умолчанию в своем первом объявлении,
- неявно считается constexpr, если неявное объявление будет,
- неявно считается, что он имеет ту же спецификацию исключений, как если бы она была неявно объявлена (15.4), …
Но затем, в C++ 11 §15.4 / 14, логика быстро переходит
Неявно объявленная специальная функция-член (раздел 12) должна иметь спецификацию исключения. Если
f
является неявно объявленным конструктором по умолчанию, конструктором копирования, конструктором перемещения, деструктором, оператором назначения копирования или оператором назначения перемещения, его неявная спецификация исключения определяет идентификатор типаT
если и только еслиT
допускается спецификацией исключений для функции, непосредственно вызываемойf
неявное определение;f
должен разрешать все исключения, если любая функция, которую он непосредственно вызывает, разрешает все исключения, иf
не должно допускать никаких исключений, если каждая функция, которую она непосредственно вызывает, не допускает никаких исключений.
В значении стандарта "разрешить" речь идет о явном разрешении через спецификацию исключений.
Если f
вызывает две функции, одна из которых определяет и, следовательно, позволяет T
и один из которых допускает все исключения, то f
должны оба указать T
и разрешить все исключения, что невозможно.
Так что это определенно выглядит как дефект в стандарте.
Я нашел соответствующий отчет о дефектах, http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html.
Тем не менее, похоже, что эта область просто большой беспорядок.:-(