308 votes

Le mot-clé static et de ses diverses utilisations en C++

Le mot-clé static est celui qui a plusieurs significations en C++ que je trouve très confus et je ne peux jamais plier mon esprit autour de comment son supposé travailler.

De ce que j'ai compris, il n'y static durée de stockage, ce qui signifie qu'il dure pour toute la durée du programme dans le cas d'un mondial, mais quand vous parlez d'un local, cela signifie qu'il est initialisé à zéro par défaut.

La Norme C++ dit cela pour les membres de données de classe avec le mot-clé static:

3.7.1 Statique de la durée de stockage [de base.stc.statique]

3 Le mot-clé static peut être utilisé pour déclarer une variable locale statique de la durée de stockage.

4 Le mot-clé statique appliqué à une classe membre de données dans une définition de classe donne la donnée membre statique de la durée de stockage.

Ce qui signifie-t-il avec une variable locale? Est une fonction de variable locale? Parce qu'il y a aussi que, lorsque vous déclarez une fonction locale comme static que c'est seulement initialisé une fois, la première fois qu'il entre dans cette fonction.

Elle aussi ne parle que de la durée de stockage en ce qui concerne les membres de la classe, qu'en est-il de la non instance spécifique, c'est aussi une propriété de l' static non? Ou est que la durée de stockage?

Maintenant, qu'en est-il avec static et de la portée du fichier? Sont toutes les variables globales considéré comme ayant statique de la durée de stockage par défaut? La suite (à partir de la section 3.7.1) semble l'indiquer:

1 Toutes les variables qui n'ont pas de dynamique de la durée de stockage, n'ont pas de thread durée de stockage, et sont pas locales ont statique de la durée de stockage. Le stockage de ces entités doit durer pendant toute la durée du programme (3.6.2, 3.6.3)

Comment est - static se rapportent à la liaison d'une variable?

Toute cette static mot-clé est carrément déroutant, quelqu'un peut-il préciser les différents usages de l'anglais et aussi me dire quand pour initialiser un static membre de la classe?

244voto

Mooing Duck Points 27497

Variables:

static variables n'existent pas pour la "durée de vie" de l' unité de traduction qu'il est défini dans l', et:

  • Si c'est dans un espace de noms de champ d'application, alors il ne peut pas être accessible depuis n'importe quelle autre unité de traduction. Ceci est connu comme "liaison interne". (Ne pas le faire dans les en-têtes, c'est juste une idée terrible)
  • Si c'est une variable dans une fonction, il ne peut pas être accessible depuis l'extérieur de la fonction. (c'est le local, ils ont mentionné)
  • les membres de la classe ont pas de portée limitée en raison d' static, mais peut être abordée à partir de la classe ainsi comme une instance (comme std::string::npos).

Avant toute fonction dans une unité de traduction est exécutée (éventuellement après l' main début de l'exécution), les variables statiques de durée de stockage dans l'unité de traduction sera constant "initialisé" ( constexpr , si possible, ou zéro sinon), et puis des gens d'autres sont "dynamique initialisé correctement dans l'ordre qu'ils sont définis dans l'unité de traduction (pour des choses comme l' std::string="HI"; qui ne sont pas constexpr). Enfin, la fonction locale de la statique sont initialisés de la première exécution de l'heure "arrive" à la ligne où elles sont déclarées. Ils sont tous détruits dans l'ordre inverse de l'initialisation.

La façon la plus simple pour obtenir tout cela est de faire de toutes les variables statiques qui ne sont pas constexpr initialisé dans la fonction statique de la population locale, ce qui permet de s'assurer tous vos statique/globales sont initialisées correctement lorsque vous essayez d'utiliser n'importe quoi, empêchant ainsi l' initialisation statique afin fiasco.

T& get_global() {
    static T global = initial_value();
    return global;
}

Soyez prudent, car lors de la spécification dit espace de noms-champ d'application les variables ont une "durée de stockage statique" par défaut, ils signifient la "durée de vie de l'unité de traduction" peu, mais cela ne veut pas dire qu'il ne peut pas être accessible à l'extérieur du fichier.

Fonctions

Beaucoup plus simple, static est souvent utilisé comme une fonction membre de classe, et très rarement utilisé pour un libre-debout fonction.

Une fonction membre statique diffère d'un membre régulier de la fonction qu'elle peut être appelée sans une instance d'une classe, et depuis, il n'a pas d'instance, il ne peut pas accéder aux non-membres statiques de la classe. Les variables statiques sont utiles lorsque vous souhaitez disposer d'une fonction d'une classe qui ne fait absolument pas référence à tous les membres de l'instance, ou pour la gestion de l' static variables membres.

struct A {
    A() {++A_count;}
    A(const A&) {++A_count;}
    A(A&&) {++A_count;}
    ~A() {--A_count;}

    static int get_count() {return A_count;}
private:
    static int A_count;
}

int main() {
    A var;

    int c0 = var.get_count(); //some compilers give a warning, but it's ok.
    int c1 = A::get_count(); //normal way
}

Un static gratuit-fonction signifie que la fonction ne peut être saisi par toute autre unité de traduction, et donc le linker peut l'ignorer totalement. Cela a un petit nombre de buts:

  • Peut être utilisé dans un fichier cpp afin de garantir que la fonction n'est jamais utilisé à partir de n'importe quel autre fichier.
  • Peut être mis dans un en-tête et de chaque fichier possède son propre exemplaire de la fonction. Pas utile, car inline fait à peu près la même chose.
  • Accélère le lien du temps en réduisant le travail
  • Peut mettre une fonction avec le même nom dans chaque TU, et ils peuvent tous faire des choses différentes. Par exemple, vous pourriez mettre un static void log(const char*) {} dans chaque fichier cpp, et ils pouvaient tous les journaux d'une manière différente.

83voto

Luchian Grigore Points 136646

Statique de la durée de stockage signifie que la variable se trouve dans le même endroit de la mémoire à travers la durée de vie du programme.

Le couplage est orthogonal à ce.

Je pense que c'est la distinction la plus importante que vous pouvez faire. Comprendre cela et le reste, ainsi que de souvenir, devrait venir facilement (ne pas répondre à @Tony directement, mais celui qui peut lire cela dans le futur).

Le mot-clé static peut être utilisé pour désigner une liaison interne et de stockage statique, mais en essence, ils sont différents.

Ce qui signifie-t-il avec une variable locale? Est une fonction de variable locale?

Oui. Indépendamment du moment où la variable est initialisée (sur le premier appel à la fonction et lors de l'exécution de chemin atteint le point de déclaration), il va résider dans la même place en mémoire pour la durée de vie du programme. Dans ce cas, static lui donne du stockage statique.

Maintenant, quelle est le cas de la statique et de la portée du fichier? Sont toutes les variables globales considéré comme ayant statique de la durée de stockage par défaut?

Oui, toutes les variables globales ont, par définition statique de la durée de stockage (maintenant que nous avons éclairci ce que cela signifie). Mais l'étendue de l'espace de noms de variables ne sont pas déclarées avec static, parce que ce serait leur donner une liaison interne, donc une variable par unité de traduction.

Comment statique se rapportent à la liaison d'une variable?

Il donne de l'espace de noms d'étendue variables de liaison interne. Il donne aux membres et les variables locales statiques durée de stockage.

Nous allons étendre sur tout cela:

//

static int x; //internal linkage
              //non-static storage - each translation unit will have its own copy of x
              //NOT A TRUE GLOBAL!

int y;        //static storage duration (can be used with extern)
              //actual global
              //external linkage
struct X
{
   static int x;     //static storage duration - shared between classes
};

void foo()
{
   static int x;     //static storage duration - shared between calls
}

L'ensemble de ce mot-clé static est carrément déroutant

Certainement, sauf si vous êtes familier avec elle. :) En essayant d'éviter d'ajouter de nouveaux mots clés à la langue, le comité ré-utilisé celui-ci, de l'OMI, à cet effet, - de la confusion. Il est utilisé pour signifier différentes choses (pourrais-je dire, probablement adverse choses).

24voto

Maciej Stachowski Points 843

C'est en fait assez simple. Si vous déclarez une variable statique dans le champ d'application d'une fonction, sa valeur est conservée entre les appels successifs à la fonction. Donc:

int myFun()
{
static int i=5;
i++;
return i;
}
int main()
{
printf("%d", myFun());
printf("%d", myFun());
printf("%d", myFun());
}

montrera 678 au lieu de 666, parce qu'il se souvient de la valeur incrémentée.

Comme pour les membres statiques, ils conservent leur valeur à travers des instances de la classe. Donc le code suivant:

struct A
{
static int a;
};
int main()
{
A first;
A second;
first.a = 3;
second.a = 4;
printf("%d", first.a);
}

imprime 4, parce que, d'abord.un et le deuxième.un sont essentiellement la même variable. Comme pour l'initialisation, voir à cette question.

13voto

Nik Bougalis Points 7521

Lorsque vous déclarez une static variable à portée de fichier, alors que cette variable n'est disponible que dans que fichier particulier (techniquement, l' *unité de traduction, mais il ne faut pas compliquer c'est trop). Par exemple:

a.cpp

static int x = 7;

void printax()
{
    cout << "from a.cpp: x=" << x << endl;
}

b.cpp

static int x = 9;

void printbx()
{
    cout << "from b.cpp: x=" << x << endl;
}

main.cpp:

int main(int, char **)
{
    printax(); // Will print 7
    printbx(); // Will print 9

    return 0;
}

Pour un local variable, static signifie que la variable sera initialisée et conserver sa valeur entre deux appels:

unsigned int powersoftwo()
{
    static unsigned lastpow;

    if(lastpow == 0)
        lastpow = 1;
    else
        lastpow *= 2;

    return lastpow;
}

int main(int, char **)
{
    for(int i = 0; i != 10; i++)
        cout << "2^" << i << " = " << powersoftwo() << endl;
}

Pour la classe de variables, cela signifie qu'il n'existe qu'une seule instance de cette variable qui est partagée entre tous les membres de cette classe. En fonction des autorisations, la variable peut être accessible depuis l'extérieur de la classe à l'aide de son nom complet.

class Test
{
private:
    static char *xxx;

public:
    static int yyy;

public:
    Test()
    {        
        cout << this << "The static class variable xxx is at address "
             << static_cast<void *>(xxx) << endl;
        cout << this << "The static class variable yyy is at address "
             << static_cast<void *>(&y) << endl;
    }
};

// Necessary for static class variables.
char *Test::xxx = "I'm Triple X!";
int Test::yyy = 0;

int main(int, char **)
{
    Test t1;
    Test t2;

    Test::yyy = 666;

    Test t3;
};

Marquage d'un non-classe de fonction en tant que static rend la fonction accessible uniquement à partir de ce fichier et inaccessible à partir d'autres fichiers.

a.cpp

static void printfilename()
{ // this is the printfilename from a.cpp - 
  // it can't be accessed from any other file
    cout << "this is a.cpp" << endl;
}

b.cpp

static void printfilename()
{ // this is the printfilename from b.cpp - 
  // it can't be accessed from any other file
    cout << "this is b.cpp" << endl;
}

Pour les fonctions de membre de classe, en les marquant comme l' static signifie que la fonction n'a pas besoin d'être appelée sur une instance particulière d'un objet (c'est à dire qu'il n'a pas un this pointeur).

class Test
{
private:
    static int count;

public:
    static int GetTestCount()
    {
        return count;
    };

    Test()
    {
        cout << this << "Created an instance of Test" << endl;
        count++;
    }

    ~Test()
    {
        cout << this << "Destroyed an instance of Test" << endl;
        count--;
    }
};

int Test::count = 0;

int main(int, char **)
{
    Test *arr[10] = { NULL };

    for(int i = 0; i != 10; i++)
        arr[i] = new Test();

    cout << "There are " << Test::GetTestCount << " instances of the Test class!" << endl;

    // now, delete them all except the first and last!
    for(int i = 1; i != 9; i++)
        delete arr[i];        

    cout << "There are " << Test::GetTestCount << " instances of the Test class!" << endl;

    delete arr[0];

    cout << "There are " << Test::GetTestCount << " instances of the Test class!" << endl;

    delete arr[9];

    cout << "There are " << Test::GetTestCount << " instances of the Test class!" << endl;

    return 0;
}

10voto

Jamin Grey Points 2323

Les variables statiques sont partagés entre chaque instance d'une classe, au lieu de chaque classe d'avoir leur propre variable.

class MyClass
{
    public:
    int myVar; 
    static int myStaticVar;
};

//Static member variables must be initialized. Unless you're using C++11, or it's an integer type,
//they have to be defined and initialized outside of the class like this:
MyClass::myStaticVar = 0;

MyClass classA;
MyClass classB;

Chaque instance de 'Maclasse' a leur propre "myVar", mais partagent le même 'myStaticVar'. En fait, vous n'avez même pas besoin d'une instance de Maclasse pour avoir accès à "myStaticVar', et vous pouvez y accéder en dehors de la classe comme ceci:

MyClass::myStaticVar //Assuming it's publicly accessible.

Lorsqu'il est utilisé dans une fonction d'une variable locale (et non pas comme un membre de la classe de la variable) le mot-clé static fait quelque chose de différent. Il vous permet de créer une variable persistante, sans donner de portée mondiale.

int myFunc()
{
   int myVar = 0; //Each time the code reaches here, a new variable called 'myVar' is initialized.
   myVar++;

   //Given the above code, this will *always* print '1'.
   std::cout << myVar << std::endl;

   //The first time the code reaches here, 'myStaticVar' is initialized. But ONLY the first time.
   static int myStaticVar = 0;

   //Each time the code reaches here, myStaticVar is incremented.
   myStaticVar++;

   //This will print a continuously incrementing number,
   //each time the function is called. '1', '2', '3', etc...
   std::cout << myStaticVar << std::endl;
}

C'est une variable globale en termes de persistance... mais sans être de portée mondiale/accessibilité.

Vous pouvez également avoir des fonctions statiques (dans les classes, et non autonome). Les fonctions statiques sont fondamentalement autonome des fonctions, mais à l'intérieur de la classe nom de l'espace de noms, et avec un accès privé à la catégorie de membres.

class MyClass
{
    public:
    int Func()
    {
        //...do something...
    }

    static int StaticFunc()
    {
        //...do something...
    }
};

int main()
{
   MyClass myClassA;
   myClassA.Func(); //Calls 'Func'.
   myClassA.StaticFunc(); //Calls 'StaticFunc'.

   MyClass::StaticFunc(); //Calls 'StaticFunc'.
   MyClass::Func(); //Error: You can't call a non-static member-function without a class instance!

   return 0;
}

Lorsque vous appelez un membre de la fonction, il y a un paramètre caché appelé "il", qui est un pointeur vers l'instance de la classe l'appel de la fonction. Fonctions membres statiques ne pas avoir ce paramètre caché... ils sont remboursables sans une instance de classe, mais aussi ne peut pas accéder non-statique des variables membres de la classe, parce qu'ils n'ont pas un " ce " pointeur de travailler avec. Ils ne sont pas être appelé une instance de classe.

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