222 votes

Variables statiques dans les fonctions membres

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

Étant donné la classe suivante :

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

Si je déclare plusieurs instances de A appelle-t-il foo() sur une instance incrémente la variable statique i sur toutes les instances ? Ou seulement celle sur laquelle il a été appelé ?

J'ai supposé que chaque instance aurait sa propre copie de i mais l'examen de certains codes que je possède semble indiquer le contraire.

237voto

iammilind Points 29275

Desde class A est une classe non-modèle et A::foo() est une fonction qui n'est pas un modèle. Il n'y aura qu'une seule copie de static int i à l'intérieur du programme.

Toute instance de A affectera le même i et la durée de vie de i sera maintenu 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

6 votes

Merci pour ce bon exemple ! Y aurait-il un moyen de réaliser quelque chose qui fasse que la portée de la fonction static int i spécifiques à l'instance, de sorte que, par exemple, les éléments suivants sont disponibles o1.foo(); // i = 1 y $o2.foo(); // i = 1 ... ?

18 votes

Bien que ce ne soit pas le style que vous recherchez, faire de i une donnée privée 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 le statut de i.

3 votes

Veuillez mentionner ce qui se passe si la classe et la méthode sont templatisées.

170voto

6502 Points 42700

Le mot-clé static a malheureusement plusieurs significations différentes et non liées en C++.

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

  2. Lorsqu'il est utilisé pour des données à l'intérieur d'une fonction, cela signifie que les données sont allouées de manière statique, initialisé la première fois que le bloc est entré et dure jusqu'à ce que le programme s'arrête. De plus, la variable n'est visible qu'à l'intérieur de la fonction. Cette caractéristique spéciale de la statique locale est souvent utilisée pour mettre en œuvre la construction paresseuse de singletons.

  3. Lorsqu'elle est utilisée au niveau d'une unité de compilation (module), cela signifie que la variable est comme une variable globale (c'est-à-dire qu'elle est allouée et initialisée avant l'entrée en vigueur de la directive main est exécuté et détruit après main sort) mais que la variable ne sera pas accessible ou visible dans d'autres unités de compilation .

J'ai mis l'accent sur la partie qui est la plus importante pour chaque utilisation. L'utilisation (3) est quelque peu découragée en faveur d'espaces de noms sans nom qui permettent également des déclarations de classes non exportées.

Dans votre code, le static 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 classe fonction et il n'y aura qu'une seule copie de celui-ci.

Comme il se doit iammilind Cependant, il aurait pu y avoir plusieurs instances de cette variable si la fonction était une fonction modèle (car dans ce cas, la fonction elle-même peut être présente en plusieurs exemplaires différents 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;
}

0 votes

Quelqu'un a-t-il une référence pour "somewhat discouraged in favor of unnamed namespaces" ?

6 votes

@austinmarton : La phrase "L'utilisation de static pour indiquer 'local to translation unit' est dépréciée en C++. Use unnamed namespaces instead (8.2.5.1)" est présente dans The C++ Programming Language in my edition (10th print, September 1999) à la page 819.

0 votes

@iammilind (& OP) static a effectivement plusieurs significations différentes ; cependant, je ne vois pas comment dire que ces significations sont " sans rapport " est justifié. Il signifie toujours : " N'ayez qu'un seul de ces éléments par <contexte>, qui transcende <contexte>. "

10voto

Saurabh Raoot Points 11

Variables statiques dans les fonctions

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

  • L'initialisation des variables statiques sera effectuée lors du premier appel de la fonction.

  • Une variable statique conservera sa valeur lors de multiples appels de fonctions.

  • La durée de vie de la variable statique est le programme

enter image description here

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;
}

Sortie :

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

Auto Variable

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

0voto

user2792801 Points 1

Merci pour ce bon exemple ! Y aurait-il un moyen de réaliser quelque chose qui rende la portée de static int i spécifique à l'instance, de sorte que, par exemple, o1.foo() ; // i = 1 et $o2.foo() ; // i > = 1 ... ? - Pique-nique

Je pense que l'un des seuls moyens est de créer une variable membre de la classe bool, de conditionner l'initialisation à sa valeur et de ne changer sa valeur qu'au moment de l'initialisation. Je peux imaginer un moyen potentiellement plus sophistiqué où une variable map statique a l'instance comme clé, mais cela semble un peu compliqué.

-2voto

0xbadf00d Points 2554

Réponse simplifiée :

Les variables statiques, qu'elles soient membres d'une classe (non modélisée) class ou une fonction (non modélisée), se comportent - techniquement - comme une étiquette globale dont la portée est limitée à l'élément class ou la fonction.

14 votes

Non. Les globaux sont initialisés au démarrage du programme, les statiques des fonctions sont initialisées à la première utilisation. Il s'agit d'une grand différence.

0 votes

Je ne pense pas que ce soit ce qui se passe. Cependant, cela devrait être spécifique au compilateur de toute façon.

2 votes

Dans ce cas, vous vous trompez : la norme C++ 3.6.1 stipule que la construction d'un objet de l'espace de nom avec une durée de stockage statique a lieu au démarrage ; la norme 6.7 (4) stipule qu'en général "... une telle variable est initialisée la première fois que le contrôle passe par sa déclaration ; une telle variable est considérée comme initialisée à la fin de son initialisation". Au fait, cette initialisation à la première utilisation est très pratique pour mettre en œuvre la construction paresseuse de singleton.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X