No final da palestra de Scott Schurr "Apresentando constexpr
" na CppCon , ele pergunta "Existe uma maneira de envenenar uma função"? Ele então explica que isso pode ser feito (embora de uma forma não padronizada) por:
- Colocando um
throw
em umaconstexpr
função - Declarando um não resolvido
extern const char*
- Referenciando o não resolvido
extern
nothrow
Sinto que estou um pouco perdido aqui, mas estou curioso:
- O que significa "envenenar uma função"?
- Qual é o significado / utilidade da técnica que ele descreve?
constexpr
função sejam avaliadas em tempo de compilação.constexpr
função pode ser usada tanto em tempo de compilação quanto em tempo de execução. Então essa é uma forma de forçá-lo para que você não possa usá-lo em tempo de execução? Quando isso é útil?constexpr
função geralmente não é a implementação mais eficiente por causa das restrições, portanto, pode-se não querer que ela seja avaliada em tempo de execução; ou, talvez seja o caso de erro (como em seu exemplo).Respostas:
Em geral, refere-se a tornar uma função inutilizável, por exemplo, se você deseja banir o uso de alocação dinâmica em um programa, você pode "envenenar" a
malloc
função para que ela não possa ser usada.No vídeo ele está usando de uma forma mais específica, o que fica claro se você ler o slide que é exibido quando ele fala sobre o envenenamento da função, que diz "Uma forma de forçar apenas o tempo de compilação?"
Então, ele está falando sobre "envenenar" a função para torná-la inviável em tempo de execução, portanto, só pode ser chamada em expressões constantes. A técnica é ter um branch na função que nunca é usado quando chamado em um contexto de tempo de compilação, e fazer com que esse branch contenha algo que irá causar um erro.
Uma
throw
expressão é permitida em uma função constexpr, desde que nunca seja alcançada durante as invocações em tempo de compilação da função (porque você não pode lançar uma exceção em tempo de compilação, é uma operação inerentemente dinâmica, como alocar memória). Portanto, uma expressão de lançamento que se refere a um símbolo indefinido não será usada durante as invocações em tempo de compilação (porque haveria falha na compilação) e não pode ser usada em tempo de execução, porque o símbolo indefinido causa um erro de vinculador.Como o símbolo indefinido não é "usado por odr" nas invocações de tempo de compilação da função, na prática o compilador não criará uma referência ao símbolo, portanto, não há problema em ser indefinido.
Isso é útil? Ele está demonstrando como fazer isso, não necessariamente dizendo que é uma boa ideia ou amplamente útil. Se você precisar fazer isso por algum motivo, a técnica dele pode resolver o seu problema. Se você não precisa disso, não precisa se preocupar com isso.
Um motivo pelo qual pode ser útil é quando a versão de tempo de compilação de alguma operação não é tão eficiente quanto poderia ser. Existem restrições sobre os tipos de expressões permitidas em uma função constexpr (especialmente em C ++ 11, algumas restrições foram removidas em C ++ 14). Portanto, você pode ter duas versões de uma função para realizar um cálculo, uma que é ideal, mas usa expressões que não são permitidas em uma função constexpr e uma que é uma função constexpr válida, mas teria um desempenho ruim se chamada em run- Tempo. Você pode envenenar o subótimo para garantir que nunca seja usado para chamadas de tempo de execução, garantindo que a versão mais eficiente (não constexpr) seja usada para chamadas de tempo de execução.
NB O desempenho de uma função constexpr usada em tempo de compilação não é realmente importante, porque ela não tem sobrecarga de tempo de execução de qualquer maneira. Isso pode tornar sua compilação mais lenta, fazendo com que o compilador faça um trabalho extra, mas não terá nenhum custo de desempenho em tempo de execução.
fonte
'Envenenar' um identificador significa que qualquer referência ao identificador após o 'envenenamento' é um erro rígido do compilador. Esta técnica pode ser usada, por exemplo, para depreciação total (a função ESTÁ obsoleta, nunca use-a!).
Em GCC tradicionalmente houve uma pragma para isso:
#pragma GCC poison
.fonte