Поделиться через


/Zc:implicitNoexcept (неявные спецификаторы исключений)

При указании параметра /Zc:implicitNoexcept компилятор добавляет неявный описатель исключений noexcept в определяемые компилятором специальные функции-члены и в определяемые пользователем деструкторы и деструкторы сделки. По умолчанию параметр /Zc:implicitNoexcept включен для соответствия стандарту ISO C++11. Отключение этого параметра отключает неявный noexcept для пользовательских деструкторов и методов освобождения, а также заданных компилятором специальных функций-членов.

Синтаксис

/Zc:implicitNoexcept[-]

Замечания

/Zc:implicitNoexcept сообщает компилятору следовать разделу 15.4 стандарта ISO C++11. Он неявно добавляет noexcept описателя исключений в каждую неявно объявленную или явно объявленную по умолчанию специальную функцию-член ( конструктор по умолчанию, конструктор копирования, конструктор перемещения, деструктор, оператор назначения копирования или оператор назначения перемещения) и каждую определяемую пользователем функцию деструктора или деструкатора. Определяемый пользователем метод освобождения содержит неявный описатель исключения noexcept(true). Для пользовательских деструкторов неявный описатель исключение — noexcept(true), если во внутреннем классе члена или базовом классе нет деструктора, отличного от типа noexcept(true). Если для созданных компилятором специальных функций-членов любая функция, вызываемая напрямую этой функцией, фактически является noexcept(false), а неявный описатель исключения — noexcept(false). Иначе неявный описатель исключение — noexcept(true).

Компилятор не создает неявный описатель исключения для функций, объявленных с явными описателями noexcept и throw или атрибутом __declspec(nothrow).

По умолчанию включен параметр /Zc:implicitNoexcept . Параметр /permissive- не влияет на /Zc:implicitNoexcept.

Если параметр отключен путем указания /Zc:implicitNoexcept-, не создаются неявными описателями исключений компилятором. То же самое происходит в Visual Studio 2013, где в деструкторах и методах освобождения без описателей исключений могли быть операторы throw. По умолчанию и при указании /Zc:implicitNoexcept , если throw оператор встречается во время выполнения в функции с неявным noexcept(true) описателям, он вызывает немедленное вызов std::terminateи обычное поведение очистки для обработчиков исключений не гарантируется. Чтобы определить эту ситуацию, компилятор создает предупреждение компилятора (уровень 1) C4297. throw Если это намеренно, рекомендуется изменить объявление функции на наличие явного noexcept(false) описателя вместо использования /Zc:implicitNoexcept-.

В этом примере показано, как определяемый пользователем деструктор, не имеющий явного описателя исключений, ведет себя при установке или отключении параметра /Zc:implicitNoexcept . Чтобы показать поведение при установке, выполните компиляцию с помощью cl /EHsc /W4 implicitNoexcept.cpp. Чтобы показать поведение при отключении, выполните компиляцию с помощью cl /EHsc /W4 /Zc:implicitNoexcept- implicitNoexcept.cpp.

// implicitNoexcept.cpp
// Compile by using: cl /EHsc /W4 implicitNoexcept.cpp
// Compile by using: cl /EHsc /W4 /Zc:implicitNoexcept- implicitNoexcept.cpp

#include <iostream>
#include <cstdlib>      // for std::exit, EXIT_FAILURE, EXIT_SUCCESS
#include <exception>    // for std::set_terminate

void my_terminate()
{
    std::cout << "Unexpected throw caused std::terminate" << std::endl;
    std::cout << "Exit returning EXIT_FAILURE" << std::endl;
    std::exit(EXIT_FAILURE);
}

struct A {
    // Explicit noexcept overrides implicit exception specification
    ~A() noexcept(false) {
        throw 1;
    }
};

struct B : public A {
    // Compiler-generated ~B() definition inherits noexcept(false)
    ~B() = default;
};

struct C {
    // By default, the compiler generates an implicit noexcept(true)
    // specifier for this user-defined destructor. To enable it to
    // throw an exception, use an explicit noexcept(false) specifier,
    // or compile by using /Zc:implicitNoexcept-
    ~C() {
        throw 1; // C4297, calls std::terminate() at run time
    }
};

struct D : public C {
    // This destructor gets the implicit specifier of its base.
    ~D() = default;
};

int main()
{
    std::set_terminate(my_terminate);

    try
    {
        {
            B b;
        }
    }
    catch (...)
    {
        // exception should reach here in all cases
        std::cout << "~B Exception caught" << std::endl;
    }
    try
    {
        {
            D d;
        }
    }
    catch (...)
    {
        // exception should not reach here if /Zc:implicitNoexcept
        std::cout << "~D Exception caught" << std::endl;
    }
    std::cout << "Exit returning EXIT_SUCCESS" << std::endl;
    return EXIT_SUCCESS;
}

При компиляции с помощью параметра по умолчанию /Zc:implicitNoexcept пример создает этот результат:

~B Exception caught
Unexpected throw caused std::terminate
Exit returning EXIT_FAILURE

При компиляции с помощью параметра /Zc:implicitNoexcept-пример создает следующие выходные данные:

~B Exception caught
~D Exception caught
Exit returning EXIT_SUCCESS

Дополнительные сведения о вопросах соответствия в Visual C++ см. в статье Nonstandard Behavior.

Установка данного параметра компилятора в среде разработки Visual Studio

  1. Откройте диалоговое окно Страницы свойств проекта. Подробнее см. в статье Настройка компилятора C++ и свойства сборки в Visual Studio.

  2. Перейдите на страницу свойств Свойства конфигурации>C/C++>Командная строка.

  3. Измените свойство "Дополнительные параметры", чтобы включить /Zc:implicitNoexcept или /Zc:implicitNoexcept- и нажмите кнопку "ОК".

См. также

/Zc (соответствие)
noexcept
Спецификации исключений (throw)
terminate