Um recurso do C ++ é a capacidade de criar namespaces não nomeados (anônimos), assim:
namespace {
int cannotAccessOutsideThisFile() { ... }
} // namespace
Você pensaria que esse recurso seria inútil - já que você não pode especificar o nome do espaço para nome, é impossível acessar qualquer coisa nele de fora. Mas esses espaços de nome sem nome são acessíveis no arquivo em que são criados, como se você tivesse uma cláusula implícita de uso.
Minha pergunta é: por que ou quando isso seria preferível ao uso de funções estáticas? Ou são essencialmente duas maneiras de fazer exatamente a mesma coisa?
c++
namespaces
Head Geek
fonte
fonte
static
desse contexto não foi preterido ; embora o espaço para nome sem nome seja uma alternativa superiorstatic
, há casos em que falha quando sestatic
trata de resgate .Respostas:
O Padrão C ++ lê na seção 7.3.1.1 Namespaces sem nome, parágrafo 2:Estático se aplica apenas a nomes de objetos, funções e uniões anônimas, não a declarações de tipo.
Editar:
A decisão de descontinuar esse uso da palavra-chave estática (afetar a visibilidade de uma declaração variável em uma unidade de tradução) foi revertida ( ref ). Nesse caso, o uso de um espaço de nome estático ou sem nome voltou a ser essencialmente duas maneiras de fazer exatamente a mesma coisa. Para mais discussões, consulte esta questão SO.
Os espaços para nome sem nome ainda têm a vantagem de permitir definir tipos de unidades de tradução locais. Por favor, veja esta pergunta para mais detalhes.
O crédito é para Mike Percy por trazer isso à minha atenção.
fonte
namespace
s sem nome implicitamente têm ligação interna, portanto não deve haver diferença. Quaisquer problemas que possam ter surgido anteriormente de palavras incorretas foram resolvidos, tornando isso um requisito no C ++ 11.A colocação de métodos em um espaço de nome anônimo evita que você viole acidentalmente a Regra de Uma Definição , permitindo que você nunca se preocupe em nomear seus métodos auxiliares da mesma forma que outros métodos aos quais você pode vincular.
E, como apontado por luke, os espaços para nome anônimos são preferidos pelo padrão sobre os membros estáticos.
fonte
Há um caso extremo em que a estática tem um efeito surpreendente (pelo menos para mim). O padrão C ++ 03 declara em 14.6.4.2/1:
O código abaixo chamará
foo(void*)
e nãofoo(S const &)
como você poderia esperar.Em si, isso provavelmente não é tão importante, mas destaca que, para um compilador C ++ totalmente compatível (ou seja, um com suporte para
export
), astatic
palavra - chave ainda terá uma funcionalidade que não está disponível de nenhuma outra maneira.A única maneira de garantir que a função em nosso namespace não nomeado não seja encontrada em modelos usando ADL é fazê-lo
static
.Atualização para C ++ moderno
A partir do C ++ '11, os membros de um espaço para nome sem nome têm vínculo interno implicitamente (3.5 / 4):
Mas, ao mesmo tempo, 14.6.4.2/1 foi atualizado para remover a menção de ligação (retirada do C ++ '14):
O resultado é que essa diferença específica entre membros estáticos e sem nome do espaço para nome não existe mais.
fonte
NS::S
trabalhar, nãoS
precisa não estar lá dentronamespace {}
?Recentemente, comecei a substituir palavras-chave estáticas por namespaces anônimos no meu código, mas imediatamente tive um problema em que as variáveis no namespace não estavam mais disponíveis para inspeção no meu depurador. Eu estava usando o VC60, então não sei se isso é um problema com outros depuradores. Minha solução alternativa foi definir um espaço para nome 'module', no qual dei o nome do meu arquivo cpp.
Por exemplo, no meu arquivo XmlUtil.cpp, defino um espaço
XmlUtil_I { ... }
para nome para todas as minhas variáveis e funções do módulo. Dessa forma, posso aplicar aXmlUtil_I::
qualificação no depurador para acessar as variáveis. Nesse caso, o_I
distingue de um espaço para nome público como oXmlUtil
que eu posso querer usar em outro lugar.Suponho que uma desvantagem potencial dessa abordagem, em comparação com uma abordagem verdadeiramente anônima, é que alguém pode violar o escopo estático desejado usando o qualificador de espaço para nome em outros módulos. Não sei se isso é uma grande preocupação.
fonte
#if DEBUG namespace BlahBlah_private { #else namespace { #endif
, portanto, o "namespace do módulo" está presente apenas nas compilações de depuração e o namespace anônimo verdadeiro é usado de outra forma. Seria bom se os depuradores dessem uma boa maneira de lidar com isso. O oxigênio também fica confuso com ele.O uso da palavra-chave estática para esse fim foi descontinuado pelo padrão C ++ 98. O problema com a estática é que ela não se aplica à definição de tipo. Também é uma palavra-chave sobrecarregada usada de maneiras diferentes em contextos diferentes, para que os namespaces sem nome simplifiquem um pouco as coisas.
fonte
Por experiência, observarei que, embora seja a maneira C ++ de colocar funções anteriormente estáticas no espaço para nome anônimo, os compiladores mais antigos às vezes podem ter problemas com isso. Atualmente, trabalho com alguns compiladores para nossas plataformas de destino, e o compilador Linux mais moderno é bom em colocar funções no espaço para nome anônimo.
Mas um compilador mais antigo em execução no Solaris, com o qual estamos casados até uma versão futura não especificada, às vezes o aceita e outras vezes o sinaliza como um erro. O erro não é o que me preocupa, é o que ele pode estar fazendo quando o aceita . Então, até que nos tornemos modernos em geral, ainda estamos usando funções estáticas (geralmente com escopo de classe) onde preferimos o espaço para nome anônimo.
fonte
Além disso, se alguém usar uma palavra-chave estática em uma variável como este exemplo:
Não seria visto no arquivo de mapeamento
fonte
Uma diferença específica do compilador entre namespaces anônimos e funções estáticas pode ser vista compilando o código a seguir.
Compilando este código com o VS 2017 (especificando o sinalizador de aviso de nível 4 / W4 para ativar o aviso C4505: a função local não referenciada foi removida ) e o gcc 4.9 com o sinalizador -Wunused-function ou -Wall mostra que o VS 2017 produzirá apenas um aviso para a função estática não utilizada. O gcc 4.9 e superior, assim como o clang 3.3 e superior, produzirão avisos para a função não referenciada no espaço para nome e também um aviso para a função estática não utilizada.
Demonstração ao vivo do gcc 4.9 e MSVC 2017
fonte
Pessoalmente, prefiro funções estáticas do que os namespaces sem nome pelos seguintes motivos:
É óbvio e claro, apenas pela definição da função, que é privado para a unidade de tradução onde é compilado. Com espaço para nome sem nome, você pode precisar rolar e procurar para ver se uma função está em um espaço para nome.
Funções em espaços para nome podem ser tratadas como externas por alguns compiladores (mais antigos). No VS2017 eles ainda são externos. Por esse motivo, mesmo que uma função esteja no namespace sem nome, você ainda pode querer marcá-las como estáticas.
As funções estáticas se comportam de maneira muito semelhante em C ou C ++, enquanto os namespaces sem nome são obviamente apenas em C ++. namespaces sem nome também adicionam nível extra no recuo e eu não gosto disso :)
Portanto, fico feliz em ver que o uso de static para funções não é mais preterido .
fonte
static
palavra - chave aplica o vínculo local a uma função. Além disso, certamente apenas um lunático delirante acrescentaria recuo para namespaces?Tendo aprendido esse recurso apenas agora enquanto lê sua pergunta, só posso especular. Isso parece fornecer várias vantagens sobre uma variável estática no nível do arquivo:
Eu estaria interessado em saber se alguém usou namespaces anônimos em código real.
fonte
A diferença é o nome do identificador desconfigurado (
_ZN12_GLOBAL__N_11bE
vs_ZL1b
, o que realmente não importa, mas os dois são montados em símbolos locais na tabela de símbolos (ausência de.global
diretiva asm).Quanto a um espaço de nome anônimo aninhado:
Todos os namespaces anônimos de 1º nível na unidade de tradução são combinados entre si, Todos os namespaces anônimos anônimos de 2º nível na unidade de tradução são combinados entre si
Você também pode ter um espaço para nome aninhado (em linha) em um espaço para nome anônimo
Você também pode ter namespaces anônimos inline, mas até onde eu sei,
inline
um namespace anônimo tem efeito 0_ZL1b
:_Z
significa que este é um identificador mutilado.L
significa que é um símbolo local através destatic
.1
é o comprimento do identificadorb
e, em seguida, o identificadorb
_ZN12_GLOBAL__N_11aE
_Z
significa que este é um identificador mutilado.N
significa que este é um espaço para nome,12
é o tamanho do nome do espaço para nome anônimo_GLOBAL__N_1
, o nome do espaço para nome anônimo_GLOBAL__N_1
,1
o comprimento do identificadora
,a
o identificadora
eE
fecha o identificador que reside em um espaço para nome._ZN12_GLOBAL__N_11A1aE
é o mesmo que acima, exceto que há outro nível de espaço para nome nele1A
fonte