O #pragma já fez parte do padrão C ++ 11?

140

Tradicionalmente, a maneira padrão e portátil de evitar múltiplas inclusões de cabeçalho no C ++ era / é usar o #ifndef - #define - #endifesquema de diretivas de pré-compilador, também chamado de esquema de guarda de macro (veja o trecho de código abaixo).

#ifndef MY_HEADER_HPP
#define MY_HEADER_HPP
...
#endif

Na maioria das implementações / compiladores (veja a figura abaixo), no entanto, há uma alternativa mais "elegante" que serve ao mesmo propósito que o esquema de proteção macro chamado #pragma once. #pragma oncepossui várias vantagens em comparação com o esquema de proteção macro, incluindo menos código, prevenção de conflitos de nomes e, às vezes, maior velocidade de compilação.

insira a descrição da imagem aqui

Pesquisando, percebi que, embora a #pragma oncediretiva seja suportada por quase todos os compiladores conhecidos, há uma turvação sobre se a #pragma oncediretiva faz parte do padrão C ++ 11 ou não.

Questões:

  • Alguém poderia esclarecer se a #pragma oncediretiva faz parte do padrão C ++ 11 ou não?
  • Se não faz parte do padrão C ++ 11, há planos de incluí-lo em versões posteriores (por exemplo, C ++ 14 ou posterior)?
  • Também seria bom se alguém pudesse aprofundar as vantagens / desvantagens no uso de qualquer uma das técnicas (por exemplo, proteção macro versus #pragma once).
101010
fonte
9
Aliás, o uso de sublinhados duplos para os protetores de cabeçalho é proibido pelo padrão, que reserva para a implementação todos os símbolos que começam com sublinhado duplo (além de outros).
Matteo Italia
9
O uso de um sublinhado à esquerda seguido de uma letra maiúscula também é barrado. Segundo, onde está a turbidez? Acabei de ver o suporte do compilador, não vejo ninguém afirmando que faz parte do padrão?
Yakk - Adam Nevraumont
1
Para o terceiro marcador, observe a questão relacionada: #pragma já foi seguro incluir guarda? Houve uma situação em que os guardas do cabeçalho funcionam, mas #pragma oncegeralmente não.
User1942027
1
possível duplicado , pois responde a essa pergunta sem mencionar o C ++ 11.
Yakk - Adam Nevraumont
3
Bem, ele não está codificado em nenhum documento oficial, mas você pode considerá-lo como padrão de fato .
Siyuan Ren

Respostas:

107

#pragma oncenão é padrão. É uma extensão generalizada (mas não universal), que pode ser usada

  • se suas preocupações com portabilidade forem limitadas e
  • você pode ter certeza de que todos os seus arquivos de inclusão estão sempre em um disco local.

Foi considerado para padronização, mas rejeitado porque não pode ser implementado com confiabilidade. (Os problemas ocorrem quando você tem arquivos acessíveis através de várias montagens remotas diferentes.)

É bastante fácil garantir que não haja conflitos de guarda de inclusão em um único desenvolvimento. Para bibliotecas, que podem ser usadas por muitos desenvolvimentos diferentes, a solução óbvia é gerar muitos caracteres aleatórios para o guarda de inclusão quando você o criar. (Um bom editor pode ser configurado para fazer isso sempre que você abrir um novo cabeçalho.) Mas mesmo sem isso, ainda não encontrei problemas com conflitos entre bibliotecas.

James Kanze
fonte
11
Não apenas montagens remotas. Hardlinks, softlinks, construções subst (no Windows). Pode ficar muito confuso.
Tonny
45
Por que o compilador não pode usar as somas de verificação SHA-1 ou MD5 para identificar os arquivos?
Sergey
29
Realmente não vejo sentido em não colocar algo no padrão se todos os principais compiladores o suportam. Na verdade, existem coisas no padrão muito menos suportadas que isso. Além disso, parece bastante bobagem reclamar sobre problemas de borda, quando estamos falando de arquivos de inclusão, onde os conflitos de nome de arquivo já são um grande problema. Seria bom se essa demanda por um recurso 100% livre de problemas tivesse sido aplicada ao conceito de #incluído arquivos de cabeçalho em geral.
TED
38
Se o seu código incluir algum arquivo de locais diferentes através de links simbólicos ou montagens estranhas, ele já não é portátil. Portanto, argumentar que pragma oncenão é possível implementar de maneira portável algo que não seja portátil (e nem deveria ser considerado) é mais uma bobagem do mundo invertido do C ++.
doc
7
@JoseAntonioDuraOlmos Concordo que os links simbólicos são um recurso do SO, que está fora do escopo da linguagem C ++. Daí surge a pergunta por que o comitê C ++ deve considerar algo que está fora do escopo da linguagem? Tentar garantir algo que não é de sua responsabilidade não faz sentido na OMI. O DOS suportou apenas 8 + 3 caracteres por nome de arquivo, mas ninguém argumentou que isso #includedeve ser removido, porque é possível usar cegamente a diretiva. #pragma oncenão restringe a portabilidade de forma alguma, desde que você não explore os links simbólicos para interromper a compilação.
22617 doc doc
32

A seção §16.6 da Norma ( rascunho N3936 ) descreve as #pragmadiretrizes como:

Uma diretiva de pré-processamento do formulário

# pragma pp-tokensopt new-line

faz com que a implementação se comporte de uma maneira definida pela implementação. O comportamento pode causar falha na tradução ou fazer com que o tradutor ou o programa resultante se comporte de maneira não conforme. Qualquer pragma que não seja reconhecido pela implementação é ignorado.

Basicamente, #pragma onceé uma instância específica de implementação de uma #pragmadiretiva e não, não é padrão. Ainda.

Muitas vezes, é amplamente suportado pela maioria dos "principais compiladores", incluindo GCC e Clang, e, portanto, às vezes é recomendado para evitar clichês de inclusão.

Sapato
fonte
10
Observe que você pode ambos #pragmae #defineguarda de cabeçalho.
Yakk - Adam Nevraumont
18
"Qualquer pragma que não seja reconhecido pela implementação é ignorado" . Isso significa que a mensagem: Aviso: diretiva pragma não reconhecida não está em conformidade?
Rodrigo 16/05
6
"e é, portanto, a maneira recomendada de evitar clichês de inclusão" - uma afirmação muito ousada. É uma maneira não padrão, e os benefícios de usá-la são poucos e dificilmente foram relevantes na minha experiência, então tive que tirar meu +1.
1628 Alex
19
@Yakk: Se alguém escreve #defineum protetor de cabeçalho, ele / ela NÃO tem motivos para escrever #pragma oncetambém.
Nawaz 16/05
5
@Nawaz Um compilador pode manter um cache de todos os arquivos (por caminho) que foram #pragma onced e, no caso de ser #includenovamente d, pode pular o #include(nem mesmo abrir o arquivo). O gcc faz o mesmo com os protetores de cabeçalho, mas é muito, muito frágil. O #pragmaprimeiro é fácil de fazer, o outro é difícil.
Yakk - Adam Nevraumont