Question

Une fonctionnalité de C ++ est la possibilité de créer des espaces de noms non nommés (anonymes), comme suit:

namespace {
    int cannotAccessOutsideThisFile() { ... }
} // namespace

Vous penseriez qu'une telle fonctionnalité serait inutile - puisque vous ne pouvez pas spécifier le nom de l'espace de nom, il est impossible d'accéder à quoi que ce soit en son sein depuis l'extérieur. Mais ces espaces de nom non nommés sont accessibles dans le fichier dans lequel ils ont été créés, comme si vous leur utilisiez une clause use implicite.

Ma question est la suivante: pourquoi ou quand cela serait-il préférable d'utiliser des fonctions statiques? Ou sont-ils essentiellement deux façons de faire exactement la même chose?

Était-ce utile?

La solution

La norme C ++ se lit dans la section 7.3.1.1 Espaces de nom non nommés, paragraphe 2:

  

L'utilisation du mot clé static est   obsolète lors de la déclaration d'objets dans un   portée de l'espace de noms, l'espace de nom non nommé   fournit une alternative supérieure.   

La statique ne s'applique qu'aux noms d'objets, de fonctions et d'unions anonymes, pas aux déclarations de type.

Modifier:

La décision de déconseiller l'utilisation du mot clé static (affectant la visibilité d'une déclaration de variable dans une unité de traduction) a été annulée ( ref ). Dans ce cas, utiliser un espace de noms statique ou non nommé revient à être essentiellement deux façons de faire exactement la même chose. Pour en savoir plus, consultez la question sur les SO 50.

.

Les espaces de noms non nommés ont toujours l'avantage de vous permettre de définir des types locaux d'unités de traduction. Veuillez consulter la question sur SO pour plus de détails.

Nous remercions Mike Percy de l'avoir signalé à mon attention.

Autres conseils

Le fait de placer des méthodes dans un espace de noms anonyme vous évite de violer accidentellement la règle de définition unique , ce qui vous permet Ne vous souciez plus jamais de nommer vos méthodes d'assistance de la même manière qu'une autre méthode à laquelle vous pouvez créer un lien.

Et, comme le souligne luke, les espaces de noms anonymes sont préférés par la norme par rapport aux membres statiques.

Il existe un cas où la statique a un effet surprenant (du moins elle l’a été pour moi). La norme C ++ 03 stipule dans 14.6.4.2/1:

  

Pour un appel de fonction dépendant d'un paramètre de modèle, si le nom de la fonction est un identificateur non qualifié mais pas un modèle-id , les fonctions candidates sont trouvées à l'aide de les règles de recherche habituelles (3.4.1, 3.4.2), sauf que:

     
      
  • Pour la partie de la recherche utilisant la recherche de nom non qualifiée (3.4.1), seules les déclarations de fonction avec une liaison externe à partir du contexte de définition de modèle sont trouvées.
  •   
  • Pour la partie de la recherche utilisant les espaces de nom associés (3.4.2), seules les déclarations de fonction avec liaison externe trouvées dans le contexte de définition de modèle ou le contexte d'instanciation de modèle sont trouvées.
  •   
     

...

Le code ci-dessous appellera foo (void *) et non pas foo (S const & amp;) comme on pouvait s'y attendre.

template <typename T>
int b1 (T const & t)
{
  foo(t);
}

namespace NS
{
  namespace
  {
    struct S
    {
    public:
      operator void * () const;
    };

    void foo (void*);
    static void foo (S const &);   // Not considered 14.6.4.2(b1)
  }

}

void b2()
{
  NS::S s;
  b1 (s);
}

En soi, ce n'est probablement pas une grosse affaire, mais cela souligne que pour un compilateur C ++ entièrement compatible (c'est-à-dire avec un support pour exporter ), le mot clé statique aura toujours des fonctionnalités qui ne sont pas disponibles de toute autre manière.

// bar.h
export template <typename T>
int b1 (T const & t);

// bar.cc
#include "bar.h"
template <typename T>
int b1 (T const & t)
{
  foo(t);
}

// foo.cc
#include "bar.h"
namespace NS
{
  namespace
  {
    struct S
    {
    };

    void foo (S const & s);  // Will be found by different TU 'bar.cc'
  }
}

void b2()
{
  NS::S s;
  b1 (s);
}

Le seul moyen de vous assurer que la fonction de notre espace de noms non nommé ne sera pas trouvée dans les modèles utilisant ADL consiste à la rendre statique .

Mise à jour pour Modern C ++

À partir de C ++ '11, les membres d'un espace de nom non nommé ont implicitement un lien interne (3.5 / 4):

  

Un espace de nom non nommé ou un espace de nom déclaré directement ou indirectement dans un espace de nom non nommé a un lien interne.

Mais au même moment, 14.6.4.2/1 a été mis à jour pour supprimer la mention de liaison (ceci provient de C ++ '14):

  

Pour un appel de fonction où l'expression postfixe est un nom dépendant, les fonctions candidates sont trouvées à l'aide de   les règles de recherche habituelles (3.4.1, 3.4.2), sauf que:

     
      
  • Pour la partie de la recherche utilisant une recherche de nom non qualifiée (3.4.1), seules les déclarations de fonction du contexte de définition du modèle sont trouvées.

  •   
  • Pour la partie de la recherche utilisant les espaces de nom associés (3.4.2), seules les déclarations de fonction trouvées dans le contexte de définition de modèle ou dans le contexte d'instanciation de modèle sont trouvées.

  •   

Le résultat est que cette différence particulière entre les membres d'espace de nom statique et non nommé n'existe plus.

J'ai récemment commencé à remplacer les mots clés statiques par des espaces de noms anonymes dans mon code, mais j'ai immédiatement rencontré un problème où les variables de l'espace de noms n'étaient plus disponibles pour l'inspection dans mon débogueur. J'utilisais VC60, donc je ne sais pas si cela ne pose aucun problème avec les autres débogueurs. Ma solution consistait à définir un espace de noms 'module', auquel je lui ai donné le nom de mon fichier cpp.

Par exemple, dans mon fichier XmlUtil.cpp, je définis un espace de nom XmlUtil_I {...} pour toutes mes variables et fonctions de module. De cette façon, je peux appliquer la qualification XmlUtil_I :: du débogueur pour accéder aux variables. Dans ce cas, le '_I' le distingue d'un espace de noms public tel que XmlUtil que je pourrais vouloir utiliser ailleurs.

Je suppose qu’un inconvénient potentiel de cette approche par rapport à une approche réellement anonyme est qu’une personne pourrait violer la portée statique souhaitée en utilisant le qualificatif d’espace de nommage dans d’autres modules. Je ne sais pas s'il s'agit d'une préoccupation majeure.

L'utilisation du mot clé static à cette fin est déconseillée par le standard C ++ 98. Le problème avec static est que cela ne s'applique pas à la définition de type. C'est également un mot clé surchargé utilisé de différentes manières dans différents contextes. Les espaces de nom non nommés simplifient donc un peu les choses.

Par expérience, je noterai simplement que, même si C ++ insère des fonctions anciennement statiques dans l’espace de noms anonyme, les compilateurs plus anciens peuvent parfois avoir des problèmes avec cela. Je travaille actuellement avec quelques compilateurs pour nos plates-formes cibles, et le compilateur Linux plus moderne convient parfaitement pour placer des fonctions dans l'espace de noms anonyme.

Mais un ancien compilateur fonctionnant sous Solaris, auquel nous sommes attachés jusqu'à une version future non spécifiée, l'acceptera parfois et le signalera parfois comme une erreur. L’erreur n’est pas ce qui m’inquiète, c’est ce qu’elle pourrait faire quand elle l’acceptera . Donc, jusqu'à ce que nous soyons modernes dans tous les domaines, nous utilisons toujours des fonctions statiques (généralement classées par classe) dans lesquelles nous préférerions l'espace de noms anonyme.

De plus, si vous utilisez un mot clé statique sur une variable comme celle-ci, par exemple:

namespace {
   static int flag;
}

Il ne serait pas visible dans le fichier de mappage

N'ayant appris cette fonctionnalité que tout à l'heure en lisant votre question, je ne peux que spéculer. Cela semble offrir plusieurs avantages par rapport à une variable statique de niveau fichier:

  • Les espaces de noms anonymes peuvent être imbriqués les uns dans les autres, offrant ainsi plusieurs niveaux de protection contre lesquels les symboles ne peuvent pas s'échapper.
  • Plusieurs espaces de noms anonymes peuvent être placés dans le même fichier source, ce qui crée différentes portées de niveau statique dans le même fichier.

J'aimerais savoir si quelqu'un a utilisé des espaces de noms anonymes dans du code réel.

Une différence spécifique du compilateur entre les espaces de noms anonymes et les fonctions statiques est visible lors de la compilation du code suivant.

#include <iostream>

namespace
{
    void unreferenced()
    {
        std::cout << "Unreferenced";
    }

    void referenced()
    {
        std::cout << "Referenced";
    }
}

static void static_unreferenced()
{
    std::cout << "Unreferenced";
}

static void static_referenced()
{
    std::cout << "Referenced";
}

int main()
{
    referenced();
    static_referenced();
    return 0;
}

Compilation de ce code avec VS 2017 (spécifiant l'indicateur d'avertissement de niveau 4 / W4 pour activer avertissement C4505: la fonction locale non référencée a été supprimée ) et gcc 4.9 avec l'indicateur -Wunused-function ou -Wall indique que VS 2017 ne produira que un avertissement pour la fonction statique inutilisée. gcc 4.9 et supérieur, ainsi que clang 3.3 et supérieur, produira des avertissements pour la fonction non référencée dans l’espace de nommage ainsi qu’un avertissement pour la fonction statique non utilisée.

Démonstration en direct de gcc 4.9 et de MSVC 2017

Personnellement, je préfère les fonctions statiques aux espaces de noms sans nom pour les raisons suivantes:

  • il ressort clairement de la définition de la fonction qu’elle est privée de l’unité de traduction où elle est compilée. Avec un espace de noms sans nom, vous devrez peut-être faire défiler et rechercher pour voir si une fonction est dans un espace de noms.

  • Les
  • fonctions dans les espaces de noms peuvent être traitées comme externes par certains compilateurs (plus anciens). Dans VS2017, ils sont toujours externes. Pour cette raison, même si une fonction est dans un espace de noms sans nom, vous pouvez toujours vouloir les marquer de manière statique.

  • Les fonctions statiques se comportent de manière très similaire en C ou C ++, alors que les espaces de noms sans nom sont évidemment uniquement en C ++. Les espaces de noms sans nom ajoutent également un niveau supplémentaire si indentation et je n'aime pas cela:)

Je suis donc heureux de voir que l'utilisation de static pour les fonctions n'est plus obsolète .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top