Quand dois-fonction au niveau des variables statiques sont alloués/initialisé?

StackOverflow https://stackoverflow.com/questions/55510

  •  09-06-2019
  •  | 
  •  

Question

Je suis tout à fait confiant que globalement, les variables déclarées obtenir alloué et initialisé, le cas échéant) au début du programme, le temps.

int globalgarbage;
unsigned int anumber = 42;

Mais qu'en statique celles définies dans une fonction?

void doSomething()
{
  static bool globalish = true;
  // ...
}

Quand est l'espace de globalish - il attribué?Je devine que lorsque le programme démarre.Mais est-il obtenir initialisé alors aussi?Ou est-ce initialisé lors de la doSomething() est d'abord appelée?

Était-ce utile?

La solution

J'étais curieux de savoir ce donc j'ai écrit le programme de test suivant et compilé avec g++ version 4.1.2.

include <iostream>
#include <string>

using namespace std;

class test
{
public:
        test(const char *name)
                : _name(name)
        {
                cout << _name << " created" << endl;
        }

        ~test()
        {
                cout << _name << " destroyed" << endl;
        }

        string _name;
};

test t("global variable");

void f()
{
        static test t("static variable");

        test t2("Local variable");

        cout << "Function executed" << endl;
}


int main()
{
        test t("local to main");

        cout << "Program start" << endl;

        f();

        cout << "Program end" << endl;
        return 0;
}

Les résultats n'étaient pas ce que j'attendais.Le constructeur de l'objet statique n'a pas été appelé jusqu'à ce que la première fois que la fonction a été appelée.Voici le résultat:

global variable created
local to main created
Program start
static variable created
Local variable created
Function executed
Local variable destroyed
Program end
local to main destroyed
static variable destroyed
global variable destroyed

Autres conseils

Quelques verbiage à partir de C++ Standard:

3.6.2 l'Initialisation de la non-objets locaux [de base.commencer.init]

1

Le stockage d'objets statiques de stockage durée (de base.stc.statique) doit être initialisé à zéro (dcl.init) avant toute autre initialisation a lieu.Les objets de POD types (de base.types) avec la durée de stockage statique initialisé avec des expressions constantes (expr.const) doit être initialisé avant tout dynamique de l'initialisation a lieu.Les objets de l'espace de noms de champ statique de stockage durée définie dans les la même unité de traduction et de manière dynamique doit être initialisé initialisé dans l'ordre de leur définition apparaît dans l'unité de traduction.[Note: dcl.init.aggr décrit l' afin de l'ensemble des membres sont initialisées.L' l'initialisation de l'locale statique des objets est décrit dans stmt.dcl. ]

[plus de texte ci-dessous en ajoutant plus de libertés pour les rédacteurs du compilateur]

6.7 Déclaration [stmt.dcl]

...

4

Le zéro de l'initialisation (dcl.init) de tous les objets locaux avec statique de la durée de stockage (de base.stc.statique est réalisée avant toute autre initialisation a lieu.Un objet local de Type de POD (de base.types) avec la durée de stockage statique initialisé avec constante-expressions est initialisé avant son le bloc est d'abord entré.Une mise en œuvre est autorisé à effectuer au début de l'initialisation d'autres objets statiques de stockage durée dans les mêmes conditions qu'une mise en œuvre est autorisés à statiquement initialiser un objet statique de stockage la durée dans l'espace de noms de la portée (de base.commencer.init).Dans le cas contraire, un objet est initialisé la première fois, le contrôle passe à travers ses déclaration;un tel objet est considéré comme initialisé lors de l' la fin de son initialisation.Si l'initialisation de la sortie lancement d'une exception, l'initialisation n'est pas complète, donc il va être essayé à nouveau la prochaine fois que le contrôle entre dans la déclaration.Si le contrôle de re-rentre dans la déclaration (de manière récursive), tandis que l'objet est initialisé, le comportement est indéfini.[Exemple:

      int foo(int i)
      {
          static int s = foo(2*i);  // recursive call - undefined
          return i+1;
      }

--fin exemple]

5

Le destructeur d'un objet local avec stockage statique de la durée être exécutée si et seulement si la variable a été construite.[Note: de base.commencer.terme décrit l'ordre dans lequel les les objets statiques durée de stockage sont détruits.]

La mémoire pour toutes les variables statiques est alloué au programme de la charge.Mais les variables statiques sont créés et initialisés la première fois qu'ils sont, non pas au début du programme jusqu'.Il y a quelques bonnes lectures sur le sujet, et de la statique en général, ici.En général, je pense que certaines de ces questions dépendent de la mise en œuvre, surtout si vous voulez savoir où en mémoire ce genre de choses sera situé.

Le compilateur alloue une variable statique(s) défini dans une fonction foo au programme de la charge, cependant, le compilateur va également ajouter quelques instructions supplémentaires (code machine) à votre fonction foo de sorte que la première fois qu'il est invoqué ce code supplémentaire initialiser la variable statique (par ex.appelant le constructeur, le cas échéant).

@Adam:Cette derrière les coulisses de l'injection de code par le compilateur est la raison pour laquelle le résultat que vous avez vu.

J'essaie de nouveau le test de code de Adam Pierce et l'ajout de plus de deux cas:variable statique dans la classe et de type POD.Mon compilateur g++ 4.8.1, dans l'OS de Windows(MinGW-32).Le résultat est variable statique dans la classe est traitée de la même avec une variable globale.Son constructeur sera appelé avant d'entrer dans la fonction principale.

  • Conclusion (pour g++, environnement Windows):

    1. Variable globale et membre statique dans la classe:le constructeur est appelé avant d'entrer principal la fonction (1).
    2. Local variable statique:le constructeur est appelé lors de l'exécution atteint sa déclaration à la première fois.
    3. Si Locale statique de la variable est de type POD, puis il est également initialisée avant d'entrer principal la fonction (1).Exemple de type POD: static int nombre = 10;

(1):Le bon état doit être: "avant tout fonction de la même unité de traduction est appelé". Cependant, pour simple, comme dans l'exemple ci-dessous, alors il est principal fonction.

inclure < iostream>

#include < string>

using namespace std;

class test
{
public:
   test(const char *name)
            : _name(name)
    {
            cout << _name << " created" << endl;
    }

    ~test()
    {
            cout << _name << " destroyed" << endl;
    }

    string _name;
    static test t; // static member
 };
test test::t("static in class");

test t("global variable");

void f()
{
    static  test t("static variable");
    static int num = 10 ; // POD type, init before enter main function

    test t2("Local variable");
    cout << "Function executed" << endl;
}

int main()
{
    test t("local to main");
    cout << "Program start" << endl;
    f();
    cout << "Program end" << endl;
    return 0;
 }

résultat:

static in class created
global variable created
local to main created
Program start
static variable created
Local variable created
Function executed
Local variable destroyed
Program end
local to main destroyed
static variable destroyed
global variable destroyed
static in class destroyed

Quelqu'un a testé sous Linux env ?

Les variables statiques sont allouées à l'intérieur d'un segment de code -- ils font partie de l'image exécutable, et donc sont mappés dans déjà initialisé.

Les variables statiques à l'intérieur de la portée de la fonction sont traités de la même façon, la portée est purement un niveau de langue de construire.

Pour cette raison, nous vous garantissons qu'une statique de la variable sera initialisée à 0 (sauf si vous spécifiez autre chose) plutôt que d'une valeur indéfinie.

Il y a quelques autres facettes de l'initialisation, vous pouvez prendre avantage de les désactiver, par exemple partagé segments permettent aux différentes instances de votre exécutable en cours d'exécution à la fois d'accéder aux mêmes variables statiques.

En C++ (étendue globale) des objets statiques ont leurs constructeurs appelés dans le cadre du programme de démarrage, sous le contrôle de la C runtime library.Sous Visual C++ au moins de l'ordre que les objets sont initialisés dans peut être contrôlée par la init_seg pragma.

Ou est-ce initialisé lors de la doSomething() est appelée en premier?

Oui, il est.Cela, entre autres choses, permet d'initialiser l'échelle mondiale d'accéder à des structures de données lorsque cela est approprié, par exemple à l'intérieur de blocs try/catch.E. g.au lieu de

int foo = init(); // bad if init() throws something

int main() {
  try {
    ...
  }
  catch(...){
    ...
  }
}

vous pouvez écrire

int& foo() {
  static int myfoo = init();
  return myfoo;
}

et de l'utiliser à l'intérieur du bloc try/catch.Sur le premier appel, la variable sera initialisée.Puis, sur la première et à côté des appels, sa valeur sera retournée (par référence).

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