Compartilhar via


/Zc:implicitNoexcept (especificadores de exceção implícitos)

Quando a opção /Zc:implicitNoexcept é especificada, o compilador adiciona um especificador de exceção noexcept implícito a funções de membro especiais definidas pelo compilador e a destruidores e desalocadores definidos pelo usuário. Por padrão, /Zc:implicitNoexcept está habilitada por questão de conformidade com o padrão ISO C++11. Desativar essa opção desabilita a noexcept implícita em destruidores e desalocadores definidos pelo usuário e funções de membro especiais definidas pelo compilador.

Sintaxe

/Zc:implicitNoexcept[-]

Comentários

/Zc:implicitNoexcept informa ao compilador para seguir a seção 15.4 do padrão ISO C++11. Ela adiciona implicitamente um especificador de exceção noexcept a cada função de membro especial declarada implicitamente ou explicitamente usada como padrão – o construtor padrão, o construtor de cópia, o construtor de movimentação, o destruidor, o operador de atribuição de cópia ou o operador de atribuição de movimentação – e cada função de destruidor ou desalocador definida pelo usuário. Um desalocador definido pelo usuário tem um especificador de exceção implícito noexcept(true). Para destruidores definidos pelo usuário, o especificador de exceção implícito é noexcept(true), a menos que uma classe de membro independente ou classe base tenha um destruidor que não seja noexcept(true). Nas funções de membro especiais geradas pelo compilador, se qualquer função invocada diretamente por essa função for efetivamente noexcept(false), o especificador de exceção implícito será noexcept(false). Caso contrário, o especificador de exceção implícito será noexcept(true).

O compilador não gera um especificador de exceção implícito para funções declaradas com especificadores noexcept ou throw explícitos ou um atributo __declspec(nothrow).

Por padrão, /Zc:implicitNoexcept está habilitada. A opção /permissive- não afeta a /Zc:implicitNoexcept.

Se a opção for desabilitada especificando /Zc:implicitNoexcept-, nenhum especificador de exceção implícito será gerado pelo compilador. Esse comportamento é semelhante ao do Visual Studio 2013, em que destruidores e desalocadores que não tinham especificadores de exceção podiam ter instruções throw. Por padrão, e quando /Zc:implicitNoexcept é especificada, se uma instrução throw for encontrada em tempo de execução em uma função com um especificador implícito noexcept(true), ela causará uma invocação imediata de std::terminate, e o comportamento normal de desenrolamento para manipuladores de exceção não será garantido. Para ajudar a identificar essa situação, o compilador gera Aviso do Compilador (nível 1) C4297. Se o throw for intencional, recomendamos que você altere sua declaração de função para ter um especificador explícito noexcept(false) em vez de usar /Zc:implicitNoexcept-.

Este exemplo mostra como um destruidor definido pelo usuário que não tem um especificador de exceção explícito se comporta quando a opção /Zc:implicitNoexcept é definida ou desabilitada. Para mostrar o comportamento quando definido, compile usando cl /EHsc /W4 implicitNoexcept.cpp. Para mostrar o comportamento quando definido, compile usando 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;
}

Quando compilado usando a configuração padrão /Zc:implicitNoexcept, o exemplo gera essa saída:

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

Quando compilado usando a configuração /Zc:implicitNoexcept-, o exemplo gera essa saída:

~B Exception caught
~D Exception caught
Exit returning EXIT_SUCCESS

Para obter mais informações sobre problemas de conformidade no Visual C++, confira Comportamento fora do padrão.

Para definir esta opção do compilador no ambiente de desenvolvimento do Visual Studio

  1. Abra a caixa de diálogo Páginas de Propriedades do projeto. Para obter detalhes, confira Definir as propriedades de build e do compilador do C++ no Visual Studio.

  2. Selecione a página de propriedades Propriedades de Configuração>C/C++>Linha de Comando.

  3. Modifique a propriedade Opções Adicionais para incluir /Zc:implicitNoexcept ou /Zc:implicitNoexcept- e escolha OK.

Confira também

/Zc (conformidade)
noexcept
Especificações de exceção (lançar)
{1&gt;terminate&lt;1}