[dcl.attr.noreturn] fornece o seguinte exemplo:
[[ noreturn ]] void f() {
throw "error";
// OK
}
mas eu não entendo qual é o objetivo [[noreturn]]
, porque o tipo de retorno da função já é void
.
Então, qual é o objetivo do noreturn
atributo? Como é que deve ser usado?
c++
c++11
attributes
noreturn
BЈовић
fonte
fonte
Respostas:
O atributo noreturn deve ser usado para funções que não retornam ao chamador. Isso não significa funções nulas (que retornam ao chamador - elas simplesmente não retornam um valor), mas funções em que o fluxo de controle não retornará à função de chamada após o término da função (por exemplo, funções que saem do aplicativo, para sempre ou faça exceções, como no seu exemplo).
Isso pode ser usado pelos compiladores para fazer algumas otimizações e gerar melhores avisos. Por exemplo, se
f
tiver o atributo noreturn, o compilador poderá avisá-lo sobre og()
código morto quando você escreverf(); g();
. Da mesma forma, o compilador saberá não avisá-lo sobre a falta de instruções de retorno após as chamadas paraf()
.fonte
execve
essa não deveria retornar, mas poderia ? Deveria ter o atributo noreturn ?noreturn
atributonoreturn
só pode ser usado se for garantido que sua função execute algo que encerra o programa antes que o fluxo de controle possa retornar ao chamador - por exemplo, porque você chama exit (), abort (), assert (0) etc.)noreturn
. Lidar com essa exceção não é o mesmo que ter retornado. Qualquer códigotry
após a chamada ainda está inacessível e, caso contráriovoid
, nenhuma atribuição ou uso do valor de retorno não ocorrerá.noreturn
não informa ao compilador que a função não retorna nenhum valor. Diz ao compilador que o fluxo de controle não retornará ao chamador . Isso permite que o compilador faça uma variedade de otimizações - ele não precisa salvar nem restaurar nenhum estado volátil da chamada, pode eliminar o código morto para eliminar qualquer código que, de outra forma, seguiria a chamada, etc.fonte
Isso significa que a função não será concluída. O fluxo de controle nunca atingirá a instrução após a chamada para
f()
:As informações podem ser usadas pelo compilador / otimizador de diferentes maneiras. O compilador pode adicionar um aviso de que o código acima é inacessível e pode modificar o código real de
g()
maneiras diferentes, por exemplo, para dar suporte a continuações.fonte
-Wno-return
e você receberá um aviso. Provavelmente não é o que você esperava, mas provavelmente é suficiente dizer que o compilador tem conhecimento do que[[noreturn]]
é e pode tirar vantagem disso. (Eu sou um pouco surpreso que-Wunreachable-code
não chutar ...)-Wmissing-noreturn
, o aviso implica que a análise de fluxo determinou questd::cout
não é alcançável. Eu não tenho um novo gcc suficiente na mão para olhar para o gerado montagem, mas eu não ficaria surpreso se a chamada paraoperator<<
foi abandonada-O1
já é o suficiente para largar esse código inacessível sem a[[noreturn]]
dica.[[noreturn]]
o código. Se essa unidade de conversão tivesse apenas uma declaração da função definida em outro lugar, o compilador não seria capaz de descartar esse código, pois não sabe que a função não retorna. É aí que o atributo deve ajudar o compilador.As respostas anteriores explicaram corretamente o que é noreturn, mas não por que ele existe. Eu não acho que os comentários de "otimização" sejam o principal objetivo: as funções que não retornam são raras e geralmente não precisam ser otimizadas. Antes, acho que a principal razão de ser do noreturn é evitar avisos falso-positivos. Por exemplo, considere este código:
Se abort () não tivesse sido marcado como "noreturn", o compilador pode ter avisado sobre esse código ter um caminho em que f não retorna um número inteiro conforme o esperado. Mas como abort () está marcado como sem retorno, ele sabe que o código está correto.
fonte
Digite teoricamente falando,
void
é o que é chamado em outros idiomasunit
outop
. Seu equivalente lógico é True . Qualquer valor pode ser legitimamente convertido paravoid
(todo tipo é um subtipo devoid
). Pense nisso como um conjunto de "universo"; não há operações em comum a todos os valores no mundo, para que não haja operações válidas em um valor do tipovoid
. Dito de outra maneira, dizer que algo pertence ao conjunto do universo não fornece nenhuma informação - você já sabe disso. Portanto, o seguinte é válido:Mas a tarefa abaixo não é:
[[noreturn]]
, Por outro lado, é chamado às vezesempty
,Nothing
,Bottom
ouBot
e é o equivalente lógico de Falso . Ele não possui valores, e uma expressão desse tipo pode ser convertida para (ou seja, é subtipo de) qualquer tipo. Este é o conjunto vazio. Observe que se alguém lhe disser "o valor da expressão foo () pertence ao conjunto vazio" é altamente informativo - informa que essa expressão nunca concluirá sua execução normal; irá abortar, jogar ou travar. É exatamente o oposto devoid
.Portanto, o seguinte não faz sentido (pseudo-C ++, pois
noreturn
não é do tipo C ++ de primeira classe)Mas a atribuição abaixo é perfeitamente legítima, pois
throw
é entendida pelo compilador como não retornando:Em um mundo perfeito, você pode usar
noreturn
como valor de retorno para a funçãoraise()
acima:Infelizmente, o C ++ não permite isso, provavelmente por razões práticas. Em vez disso, oferece a capacidade de usar
[[ noreturn ]]
atributos que ajudam a orientar otimizações e avisos do compilador.fonte
void
evoid
nunca avaliado paratrue
oufalse
ou qualquer outra coisa.true
, eu não quero dizer "o valortrue
do tipobool
" mas o sentido da lógica, ver Curry-Howard correspondência(void)true;
é perfeitamente válido, como a resposta sugere.void(true)
é algo completamente diferente, sintaticamente. É uma tentativa de criar um novo objeto do tipovoid
chamando um construtortrue
como argumento; isso falha, entre outros motivos, porquevoid
não é de primeira classe.