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

Можно ли объявить "главную" функцию с помощью спецификатора "noexcept"?

Является ли следующий код действительным в С++?

int main() noexcept
{
}

Оба clang++ 3.8.0 и g++ 7.2.0 скомпилировать его в порядке (с флагами -std=c++14 -O0 -Wall -Wextra -Werror -pedantic-errors).

Разрешено ли использовать сложные условия (например, включая оператор noexcept) в спецификации noexcept функции main?

А как насчет С++ 17? Как я знаю, спецификатор noexcept становится частью типа функции в этой редакции стандарта.

4b9b3361

Ответ 1

Стандартная [ [basic.start.main]] задает следующие ограничения для функции main:

Реализация должна допускать:

- функция(), возвращающая int и

- функция (int, указатель на указатель на char), возвращающая int

При этом:

Программа, определяющая main как удалённую или объявляющую main, является встроенной, статической или constexpr, плохо сформирована.

На практике спецификация noexcept для main отсутствует. С другой стороны, noexcept разрешен как спецификатор для любой функции. Это означало бы, что main noexcept не плохо сформировался.


Какая разница w/o noexcept main?

Поскольку стандарт не очень явственен о noexcept для функции main, как мы видели, мы можем попытаться вычесть некоторое поведение и проверить реализации.

Из здесь:

Всякий раз, когда генерируется исключение, и поиск обработчика встречается с самым внешним блоком не-бросающей функции, вызывается функция std:: terminate.

В то время как общее правило для исключений, из здесь:

Если исключение выбрано и не поймано, включая исключения, которые исключают начальную функцию std:: thread, главную функцию и конструктор или деструктор любых статических или поточно-локальных объектов, тогда вызывается std:: terminate, Реализовано определение того, происходит ли разворачивание стека для неперехваченных исключений.

Это означает, что функция throw из main всегда генерирует вызов std::terminate. Независимо от noexcept спецификации main.

Сторона реализации:

Действительно, следующие коды:

int main(int argc, char* argvp[]) {
  throw 1;
  return 0;
}

и

int main(int argc, char* argvp[]) noexcept {
  throw 1;
  return 0;
}

будет производить тот же выходной сбор. Например, в GCC:

main:
        movl    $4, %edi
        subq    $8, %rsp
        call    __cxa_allocate_exception
        xorl    %edx, %edx
        movl    $1, (%rax)
        movl    typeinfo for int, %esi
        movq    %rax, %rdi
        call    __cxa_throw

Это означает, что он будет разрешен в вызове std::terminate, потому что кадр стека пуст на "основном уровне" независимо от спецификации noexcept.

Ответ 2

Тип main in int main() noexcept; - это "функция (), возвращающая int" в С++ 14 и "noexcept функция (), возвращающая int" в С++ 17.

Первый явно требуется для поддержки [basic.start.main]. Последнее не является.

Это выглядит как дефект в С++ 17.