Подтвердить что ты не робот

По умолчанию деструктор nothrow

Следующий код не компилируется под gcc-4.7.1, а компилируется под clang-3.2. Какой из них следует стандарту С++ 11?

struct X {
  virtual ~X() = default;
};

struct Y : X {
  virtual ~Y() = default;
};

gcc-4.7.1 жалуется, что:

looser throw specifier for 'virtual Y::~Y()'
error: overriding 'virtual X::~X() noexcept(true)'

Очевидно, что gcc-4.7.1 считает, что деструктор по умолчанию не установлен, но Y-деструктор по умолчанию не является ничем. Почему это? Может ли кто-нибудь обратиться к правильному месту в стандарте? Спасибо.

Я видел похожие вопросы о stackoverflow, но я не видел ответов, ссылающихся на стандарт.

4b9b3361

Ответ 1

Компиляторы попадают в дилемму здесь по следующим причинам:

(1) Не указывать никаких исключений в объявлении функции (т.е. не использовать throw и noexcept (что эквивалентно noexcept(true))) означает, что эта функция может выбрасывать все возможные исключения:

(§15.4/12, акцент мой) Функция с исключение-спецификацией или с исключением-спецификацией формы noexcept(constant-expression), где constant-expression дает false разрешает все исключения. [...]

(2) Деструктор по умолчанию по умолчанию должен позволять точно исключение, разрешенное функциями, непосредственно вызываемыми его неявным определением:

(§ 15.4/14, акцент мой) Неявно объявленная специальная функция-член (пункт 12) должна иметь спецификацию исключения. Если f - неявно объявленный конструктор по умолчанию, конструктор копирования, конструктор перемещения, деструктор, оператор присваивания копий или оператор переадресации, его неявное исключение - спецификация определяет type-id T тогда и только тогда, когда T разрешено исключением-спецификацией функции, непосредственно вызываемой fs неявным определением; f разрешает все исключения, если какая-либо функция, которую он вызывает напрямую, допускает все исключения, а f не допускает исключений, если каждая вызываемая им функция не позволяет исключений.

(3) Когда специальный член (например, деструктор) явно дефолт, т.е. когда вы используете = default, спецификация исключения необязательная (см. использование "может иметь" ниже ):

(8.4.2/2, выделение мое) явно дефолтная функция [...] может иметь явное исключение-спецификацию только в том случае, если она совместима ( 15.4) с исключением - указание на неявное объявление. [...]

В стандарте нет инструкции, требующей спецификации исключения в явно деструкторе по умолчанию.

Заключение: Поэтому не указывать исключения явно дефолтного деструктора можно интерпретировать двумя способами:

  • Чтобы означать, что все исключения разрешены (согласно (1) выше)
  • Или, в качестве альтернативы, означать, что допускаются те же исключения, которые допускаются по неявному определению деструктора по умолчанию (согласно (3) выше), что в вашем случае означает исключение исключений (согласно (2) ) выше).

К сожалению, GCC разрешает эту дилемму одним способом (в пользу "исключений" ) в случае вашего объявления базового класса и по-другому в случае производного класса (в пользу "всех исключений" ) там).

Я считаю, что наиболее естественная интерпретация этой, по общему признанию, неоднозначной ситуации заключается в том, чтобы предположить, что (2) и (3) переопределить (1). Стандарт не говорит об этом, но должен. Под этой интерпретацией, Кланг, кажется, здесь.