Os especificadores de exceção foram descontinuados porque os especificadores de exceção geralmente são uma péssima ideia . noexceptfoi adicionado porque é o único uso razoavelmente útil de um especificador de exceção: saber quando uma função não lançará uma exceção. Assim, torna-se uma escolha binária: funções que vão lançar e funções que não vão lançar.
noexceptfoi adicionado em vez de apenas remover todos os especificadores de lançamento, exceto throw()porque noexcepté mais poderoso. noexceptpode ter um parâmetro que em tempo de compilação se transforma em um booleano. Se o booleano for verdadeiro, o valor permanece noexcept. Se o booleano for falso, o noexceptnão pega e a função pode ser lançada.
Assim, você pode fazer algo assim:
struct<typename T>
{
void CreateOtherClass() { T t{}; }
};
Faz CreateOtherClassexceções lance? Pode, se To construtor padrão puder. Como podemos saber? Como isso:
struct<typename T>
{
void CreateOtherClass() noexcept(is_nothrow_default_constructible<T>::value) { T t{}; }
};
Assim, CreateOtherClass()irá lançar iff o construtor padrão de determinado tipo lançar. Isso corrige um dos principais problemas com especificadores de exceção: sua incapacidade de propagar a pilha de chamadas.
Você não pode fazer isso com throw().
noexceptpodem ocorrer verificações de tempo de execução. A principal diferença entre eles é que a quebranoexceptcausastd::terminateenquanto a quebrathrowcausastd::unexpected. Também um comportamento de desenrolamento de pilha ligeiramente diferente nesses casos.