Variables statiques dans les fonctions membres

158

Quelqu'un peut-il expliquer comment les variables statiques dans les fonctions membres fonctionnent en C ++.

Compte tenu de la classe suivante:

class A {
   void foo() {
      static int i;
      i++;
   }
}

Si je déclare plusieurs instances de A, l'appel foo()d'une instance incrémente-t-il la variable statique isur toutes les instances? Ou seulement celui sur lequel il était appelé?

J'ai supposé que chaque instance aurait sa propre copie de i, mais parcourir un certain code que j'ai semble indiquer le contraire.

monofonik
la source

Réponses:

169

Depuis class Aest une classe non-modèle et A::foo()une fonction non-modèle. Il n'y aura qu'une seule copie de l' static int iintérieur du programme.

Toute instance d' Aobjet affectera le même iet la durée de vie de irestera tout au long du programme. Pour ajouter un exemple:

A o1, o2, o3;
o1.foo(); // i = 1
o2.foo(); // i = 2
o3.foo(); // i = 3
o1.foo(); // i = 4
iammilind
la source
3
Merci pour le bon exemple! Y aurait-il un moyen de réaliser réellement quelque chose qui rend la portée static int ispécifique à l'instance, de sorte que par exemple o1.foo(); // i = 1et $o2.foo(); // i = 1...?
Stingery
14
Bien que ce ne soit peut-être pas le style que vous recherchez, faire de ia données privées un membre de la classe A aurait l'effet que vous décrivez. Si vous êtes préoccupé par les conflits de noms, vous pouvez ajouter un préfixe tel que m_pour indiquer l'état de i.
Carl Morris
137

Le mot-clé a staticmalheureusement quelques significations différentes et indépendantes en C ++

  1. Lorsqu'il est utilisé pour les membres de données, cela signifie que les données sont allouées dans la classe et non dans les instances.

  2. Lorsqu'elles sont utilisées pour des données à l'intérieur d'une fonction, cela signifie que les données sont allouées de manière statique, initialisées la première fois que le bloc est entré et dure jusqu'à ce que le programme se ferme. De plus, la variable n'est visible qu'à l'intérieur de la fonction. Cette particularité de la statique locale est souvent utilisée pour implémenter la construction paresseuse de singletons.

  3. Lorsqu'elle est utilisée au niveau d'unité de compilation (module), cela signifie que la variable est comme une variable globale (c'est-à-dire allouée et initialisée avant d' mainêtre exécutée et détruite après les mainsorties) mais que la variable ne sera pas accessible ou visible dans d'autres unités de compilation .

J'ai ajouté un peu d'emphase sur la partie la plus importante pour chaque utilisation. Use (3) est quelque peu déconseillé en faveur des espaces de noms sans nom qui permettent également des déclarations de classe non exportées.

Dans votre code, le staticmot-clé est utilisé avec la signification numéro 2 et n'a rien à voir avec les classes ou les instances ... c'est une variable de la fonction et il n'y en aura qu'une copie.

Comme l'a correctement dit iammilind , il aurait pu y avoir plusieurs instances de cette variable si la fonction était une fonction modèle (car dans ce cas, en effet, la fonction elle-même peut être présente dans de nombreuses copies différentes dans le programme). Même dans ce cas, bien sûr, les classes et les instances ne sont pas pertinentes ... voir l'exemple suivant:

#include <stdio.h>

template<int num>
void bar()
{
    static int baz;
    printf("bar<%i>::baz = %i\n", num, baz++);
}

int main()
{
    bar<1>(); // Output will be 0
    bar<2>(); // Output will be 0
    bar<3>(); // Output will be 0
    bar<1>(); // Output will be 1
    bar<2>(); // Output will be 1
    bar<3>(); // Output will be 1
    bar<1>(); // Output will be 2
    bar<2>(); // Output will be 2
    bar<3>(); // Output will be 2
    return 0;
}
6502
la source
41
+1 pour keyword static unfortunately has a few different unrelated meanings in C++:)
iammilind
le monde a tellement plus de sens après avoir lu ceci, MERCI
Erin
J'aime l'astuce avec les modèles. J'ai hâte de trouver une excuse pour l'utiliser.
Tomáš Zato - Réintégrer Monica
Quelqu'un a obtenu une référence pour "un peu découragé en faveur d'espaces de noms sans nom"?
austinmarton
3
@austinmarton: La phrase "L'utilisation de statique pour indiquer 'l'unité de traduction locale' est obsolète en C ++. Utilisez plutôt des espaces de noms sans nom (8.2.5.1)" est présente dans le langage de programmation C ++ dans mon édition (10e édition, septembre 1999) à la page 819.
6502
2

Variables statiques à l'intérieur des fonctions

  • La variable statique est créée à l'intérieur d'une fonction est stockée dans la mémoire statique du programme et non sur la pile.

  • L'initialisation de la variable statique sera effectuée au premier appel de la fonction.

  • La variable statique conservera la valeur dans plusieurs appels de fonction

  • La durée de vie de la variable statique est Program

entrez la description de l'image ici

Exemples

#include <iostream>

using namespace std;

class CVariableTesting 
{
    public:
    
    void FuncWithStaticVariable();
    void FuncWithAutoVariable();

};

void CVariableTesting::FuncWithStaticVariable()
{
    static int staticVar = 0; //staticVar is initialised by 0 the first time
    cout<<"Variable Value : "<<staticVar<<endl;
    staticVar++;
}
void CVariableTesting::FuncWithAutoVariable()
{
    int autoVar = 0;
    cout<<"Variable Value : "<<autoVar<<endl;
    autoVar++;
}
    

int main()
{
    CVariableTesting objCVariableTesting;
    cout<<"Static Variable";
    objCVariableTesting.FuncWithStaticVariable();
    objCVariableTesting.FuncWithStaticVariable();
    objCVariableTesting.FuncWithStaticVariable();
    objCVariableTesting.FuncWithStaticVariable();
    objCVariableTesting.FuncWithStaticVariable();
    
    cout<<endl;
    cout<<"Auto Variable";
    objCVariableTesting.FuncWithAutoVariable();
    objCVariableTesting.FuncWithAutoVariable();
    objCVariableTesting.FuncWithAutoVariable();
    objCVariableTesting.FuncWithAutoVariable();
    objCVariableTesting.FuncWithAutoVariable();
    
    return 0;
}

Production :

Variable statique

Valeur de la variable: 0
Valeur de la variable: 1
Valeur de la variable: 2
Valeur de la variable: 3
Valeur de la variable: 4

Variable automatique

Valeur de la variable: 0
Valeur de la variable: 0
Valeur de la variable: 0
Valeur de la variable: 0
Valeur de la variable: 0

Saurabh Raoot
la source
-2

Réponse simplifiée:

Les variables statiques, qu'elles soient membres d'une fonction (non basée sur classun modèle) ou (sans modèle), se comportent - techniquement - comme une étiquette globale dont la portée est limitée à la classfonction ou.

0xbadf00d
la source
9
Non. Les globaux sont initialisés au démarrage du programme, les statiques des fonctions sont initialisées à la première utilisation. C'est une grosse différence.
6502
Je ne pense pas que ce soit ce qui se passe. Cependant, cela devrait être spécifique au compilateur de toute façon.
0xbadf00d
2
Alors vous pensez mal: 3.6.1 dans la norme C ++ dicte que la construction d'objet de portée d'espace de noms avec une durée de stockage statique se produit au démarrage; 6.7 (4) stipule qu'en général "... une telle variable est initialisée la première fois que la commande passe par sa déclaration; une telle variable est considérée comme initialisée à la fin de son initialisation". D'ailleurs, cette initialisation à la première utilisation est très pratique pour implémenter la construction de singleton paresseux.
6502
3.7.4: "L'initialisation constante (3.6.2) d'une entité à portée de bloc avec une durée de stockage statique, le cas échéant, est effectuée avant l'entrée de son bloc pour la première fois. Une implémentation est autorisée à effectuer une initialisation anticipée d'autres variables de portée de bloc avec durée de stockage statique ou de thread dans les mêmes conditions qu'une implémentation est autorisée à initialiser statiquement une variable avec une durée de stockage statique ou thread dans la portée de l'espace de noms (3.6.2). Sinon, une telle variable est initialisée la première commande de temps passe par sa déclaration; "
0xbadf00d
1
Curieusement cependant: 1) pour une initialisation constante, il n'est pas pertinent de discuter si une statique locale peut être initialisée avant d'entrer dans le bloc la première fois (la variable n'est visible qu'à l'intérieur du bloc et l'initialisation constante ne produit aucun effet secondaire); 2) rien dans votre message n'est dit sur l'initialisation constante; 3) la statique locale est très utile pour une initialisation non constante comme MyClass& instance(){ static MyClass x("config.ini"); return x; }- une implémentation portable valide pour une utilisation mono-thread exactement parce que la statique locale n'est PAS simplement comme un global malgré ce que vous dites.
6502 le