Você poderia dar um exemplo em que static_assert(...)
('C ++ 11') resolveria o problema em mãos elegantemente?
Estou familiarizado com o tempo de execução assert(...)
. Quando devo preferir em static_assert(...)
vez de regular assert(...)
?
Além disso, boost
existe algo chamado BOOST_STATIC_ASSERT
, é o mesmo que static_assert(...)
?
Respostas:
Em cima da minha cabeça...
Supondo que
SomeLibrary::Version
seja declarado como uma const estática, em vez de ser#define
d (como seria de esperar em uma biblioteca C ++).Contraste com ter que compilar
SomeLibrary
e seu código, link de tudo, e rodar o executável única , em seguida, para descobrir que você gastou 30 minutos compilar uma versão incompatívelSomeLibrary
.@Arak, em resposta ao seu comentário: sim, você pode
static_assert
simplesmente ficar sentado em qualquer lugar, pelo que parece:fonte
static_assert
em um contexto de não execução? Parece um exemplo muito bom :)static_assert
. Se a condição não for conhecida até que o programa seja executado, useassert
.Assert estático é usado para fazer asserções em tempo de compilação. Quando a asserção estática falha, o programa simplesmente não compila. Isso é útil em diferentes situações, como, por exemplo, se você implementar alguma funcionalidade por código que depende criticamente de um
unsigned int
objeto ter exatamente 32 bits. Você pode colocar uma declaração estática como estaem seu código. Em outra plataforma, com tipos de tamanhos diferentes,
unsigned int
a compilação falhará, chamando a atenção do desenvolvedor para a parte problemática do código e aconselhando-os a reimplementar ou inspecionar novamente.Para outro exemplo, você pode querer passar algum valor integral como um
void *
ponteiro para uma função (um hack, mas útil às vezes) e você deseja ter certeza de que o valor integral caberá no ponteiroVocê pode querer um ativo que
char
seja assinadoou aquela divisão integral com valores negativos arredondados para zero
E assim por diante.
Em muitos casos, as asserções de tempo de execução podem ser usadas em vez de asserções estáticas, mas as asserções de tempo de execução só funcionam em tempo de execução e somente quando o controle passa sobre a asserção. Por esse motivo, uma declaração de tempo de execução com falha pode permanecer inativa, sem ser detectada por longos períodos de tempo.
Obviamente, a expressão em asserção estática deve ser uma constante de tempo de compilação. Não pode ser um valor de tempo de execução. Para valores de tempo de execução, você não tem outra escolha a não ser usar o normal
assert
.fonte
static_assert
especificamente ao C ++ 11. Meustatic_assert
acima é apenas uma implementação abstrata de asserção estática. (Eu pessoalmente uso algo assim no código C). Minha resposta pretende ser sobre o propósito geral de asserções estáticas e sua diferença com as asserções de tempo de execução.unsigned int
. Isso não é garantido pelo padrão. Uma variável do tipounsigned int
poderia ocupar legalmente 32 bits de memória, deixando 16 deles sem uso (e, portanto, a macroUINT_MAX
seria igual a65535
). Portanto, a maneira como você descreve a primeira asserção estática ("unsigned int
objeto com exatamente 32 bits") é enganosa. Para corresponder a sua descrição, esta afirmação deve ser incluída, bem como:static_assert(UINT_MAX >= 0xFFFFFFFFu)
.Eu o uso para garantir que minhas suposições sobre o comportamento do compilador, cabeçalhos, libs e até mesmo meu próprio código estejam corretas. Por exemplo, aqui eu verifico se a estrutura foi compactada corretamente no tamanho esperado.
Em um embrulho classe
stdio.h
'sfseek()
, tenho tido alguns atalhos comenum Origin
e verificação de que esses atalhos alinhar com as constantes definidas pelostdio.h
Você deve preferir
static_assert
maisassert
quando o comportamento é definido em tempo de compilação, e não em tempo de execução, tais como os exemplos que eu dei acima. Um exemplo em que este não seja o caso incluiria a verificação do parâmetro e do código de retorno.BOOST_STATIC_ASSERT
é uma macro pré-C ++ 0x que gera código ilegal se a condição não for satisfeita. As intenções são as mesmas, emborastatic_assert
sejam padronizadas e possam fornecer melhores diagnósticos do compilador.fonte
BOOST_STATIC_ASSERT
é um wrapper multiplataforma parastatic_assert
funcionalidade.Atualmente estou usando static_assert para impor "Conceitos" em uma classe.
exemplo:
Isso causará um erro de tempo de compilação se qualquer uma das condições acima não for atendida.
fonte
Um uso de
static_assert
pode ser para garantir que uma estrutura (que é uma interface com o mundo exterior, como uma rede ou arquivo) tenha exatamente o tamanho que você espera. Isso pegaria casos em que alguém adiciona ou modifica um membro da estrutura sem perceber as consequências. Ostatic_assert
pegaria e alertaria o usuário.fonte
Na ausência de conceitos, pode-se usar
static_assert
para verificação de tipo de tempo de compilação simples e legível, por exemplo, em modelos:fonte
Isso não responde diretamente à pergunta original, mas é um estudo interessante sobre como aplicar essas verificações de tempo de compilação antes do C ++ 11.
Capítulo 2 (Seção 2.1) de Modern C ++ Design por Andrei Alexanderscu implementa esta ideia de asserções em tempo de compilação como esta
Compare a macro STATIC_CHECK () e static_assert ()
fonte
O
static_assert
pode ser usado para proibir o uso dadelete
palavra-chave desta forma:#define delete static_assert(0, "The keyword \"delete\" is forbidden.");
Todo desenvolvedor C ++ moderno pode querer fazer isso se quiser usar um coletor de lixo conservador usando apenas classes es e struct s que sobrecarregam o operador new para invocar uma função que aloca memória no heap conservador do coletor de lixo conservador que pode ser inicializado e instanciado invocando alguma função que faça isso no início da
main
função.Por exemplo, todo desenvolvedor C ++ moderno que deseja usar o coletor de lixo conservador Boehm-Demers-Weiser
main
escreverá no início da função:GC_init();
E em todo
class
estruct
sobrecarregaroperator new
desta forma:E agora que o
operator delete
não é mais necessário, porque o coletor de lixo conservador Boehm-Demers-Weiser é responsável por liberar e desalocar cada bloco de memória quando não for mais necessário, o desenvolvedor quer proibir odelete
palavra chave.Uma maneira é sobrecarregar
delete operator
desta forma:Mas isso não é recomendado, porque o desenvolvedor C ++ moderno saberá que ele invocou por engano o
delete operator
tempo de execução, mas é melhor saber isso logo no tempo de compilação.Portanto, a melhor solução para este cenário, na minha opinião, é usar o
static_assert
conforme mostrado no início desta resposta.Claro que isso também pode ser feito com
BOOST_STATIC_ASSERT
, mas acho questatic_assert
é melhor e deve ser sempre preferido.fonte