/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
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.
Selecione a página de propriedades Propriedades de Configuração>C/C++>Linha de Comando.
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>terminate<1}