109 votes

Quand les variables statiques de niveau fonction sont-elles allouées/initialisées ?

Je suis convaincu que les variables déclarées globalement sont allouées (et initialisées, le cas échéant) au moment du démarrage du programme.

int globalgarbage;
unsigned int anumber = 42;

Mais qu'en est-il de ceux qui sont statiques et définis dans une fonction ?

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

Quand l'espace pour globalish alloué ? Je suppose que c'est au démarrage du programme. Mais est-ce qu'il est aussi initialisé à ce moment-là ? Ou est-il initialisé lorsque doSomething() est appelé en premier ?

108voto

Adam Pierce Points 12801

Par curiosité, j'ai écrit le programme de test suivant et l'ai 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 ne sont pas ceux que j'attendais. Le constructeur de l'objet statique n'a été appelé que lors du premier appel de la fonction. 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

42 votes

A titre de précision : la variable statique est initialisée la première fois que l'exécution atteint sa déclaration, et non pas lorsque la fonction qui la contient est appelée. Si vous avez simplement une variable statique au début de la fonction (comme dans votre exemple), c'est la même chose, mais pas nécessairement : par exemple, si vous avez 'if (...) { static MyClass x ; ... }', alors 'x' ne sera pas du tout initialisé lors de la première exécution de cette fonction dans le cas où la condition de l'instruction if est évaluée à false.

7 votes

Mais cela n'entraîne-t-il pas un surcoût au niveau de l'exécution, puisque chaque fois que la variable statique est utilisée, le programme doit vérifier si elle a déjà été utilisée, et si ce n'est pas le cas, elle doit être initialisée ? Dans ce cas, ça craint un peu.

0 votes

Illustration parfaite

66voto

Arkadiy Points 10567

Quelques verbiages pertinents de la norme C++ :

3.6.2 Initialisation des objets non-locaux [basic.start.init]

1

Le stockage des objets avec un stockage statique durée ( basic.stc.static ) doit être réinitialisé à zéro ( dcl.init ) avant toute autre initialisation. Les objets de types POD ( types.de.base ) avec une durée de stockage statique initialisés avec des expressions constantes ( expr.const ) sont initialisés avant toute initialisation dynamique. Les objets de la portée de l'espace de nom avec une durée de stockage statique définis dans la même unité de traduction et initialisés dynamiquement doivent être initialisés dans l'ordre d'apparition de leur définition dans le document l'unité de traduction. [Note : dcl.init.aggr décrit le ordre dans lequel les membres de l'agrégat sont initialisés. L'adresse initialisation des objets statiques locaux est décrite dans stmt.dcl . ]

[plus de texte ci-dessous ajoutant plus de libertés pour les auteurs de compilateurs].

6.7 Déclaration [stmt.dcl]

...

4

L'initialisation zéro ( dcl.init ) de tous les objets locaux avec durée de stockage statique ( basic.stc.static ) est effectuée avant toute autre initialisation. Un objet local de type type POD ( types.de.base ) avec une durée de stockage statique initialisée avec des expressions constantes est initialisée avant que son bloc bloc soit entré pour la première fois. Une implémentation est autorisée à effectuer l'initialisation précoce d'autres objets locaux à stockage statique. statique dans les mêmes conditions qu'une implémentation est d'initialiser de façon statique un objet avec une durée de stockage statique dans la portée de l'espace de nom ( basic.start.init ). Sinon, un tel objet est initialisé la première fois que le contrôle passe par sa déclaration. déclaration ; un tel objet est considéré comme initialisé à la fin de son initialisation. l'achèvement de son initialisation. Si l'initialisation se termine par une exception, l'initialisation n'est pas terminée, elle sera donc réessayée au l'initialisation n'est pas terminée, elle sera donc réessayée la prochaine fois que le contrôle entrera dans la déclaration. Si le contrôle entre à nouveau dans la déclaration (de manière récursive) alors que l'objet est en cours d'initialisation, le comportement est indéfini. l'objet est en cours d'initialisation, le comportement est indéfini. [ Ejemplo:

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

-- exemple de fin ]

5

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

3 votes

Cela répond à ma question et ne repose pas sur des "preuves anecdotiques", contrairement à la réponse acceptée. Je cherchais spécifiquement cette mention d'exceptions dans le constructeur d'objets locaux statiques à fonction initialisée : If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration.

32voto

Eugene Points 417

La mémoire de toutes les variables statiques est allouée au chargement du programme. Mais les variables statiques locales sont créées et initialisées la première fois qu'elles sont utilisées, et non au démarrage du programme. Il existe de bonnes lectures à ce sujet, et sur les variables statiques en général, aquí . En général, je pense que certaines de ces questions dépendent de l'implémentation, en particulier si vous voulez savoir où se trouve le contenu de la mémoire.

2 votes

Pas tout à fait, les statiques locales sont allouées et initialisées à zéro "au chargement du programme" (entre guillemets, car ce n'est pas tout à fait exact non plus), puis réinitialisées la première fois que l'on entre dans la fonction dans laquelle elles se trouvent.

0 votes

Il semble que ce lien soit maintenant rompu, 7 ans plus tard.

2 votes

Oui, le lien est rompu. Voici une archive : web.archive.org/web/20100328062506/http://www.acm.org/

10voto

Henk Points 1418

Le compilateur allouera la ou les variables statiques définies dans une fonction foo au chargement du programme, mais le compilateur ajoutera également quelques instructions supplémentaires (code machine) à votre fonction foo de sorte que la première fois qu'il sera invoqué, ce code supplémentaire initialisera la variable statique (par exemple, en invoquant le constructeur, le cas échéant).

@Adam : Cette injection de code en coulisse par le compilateur est la raison du résultat que vous avez vu.

3voto

Rob Walker Points 25840

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

Les variables statiques dans la portée d'une fonction sont traitées de la même manière, la portée est purement une construction au niveau du langage.

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

Il existe d'autres facettes de l'initialisation dont vous pouvez tirer parti - par exemple, les segments partagés permettent à différentes instances de votre exécutable s'exécutant simultanément d'accéder aux mêmes variables statiques.

En C++ (globally scoped), les objets statiques voient leurs constructeurs appelés au démarrage du programme, sous le contrôle de la bibliothèque d'exécution du C. Sous Visual C++, au moins, l'ordre dans lequel les objets sont initialisés peut être contrôlé par l'attribut init_seg pragma.

6 votes

Cette question porte sur la statique à l'échelle des fonctions. Au moins lorsqu'elles ont des constructeurs non triviaux, elles sont initialisées à la première entrée dans la fonction. Ou plus précisément, lorsque cette ligne est atteinte.

0 votes

C'est vrai -- mais la question parle de l'espace alloué à la variable, et utilise des types de données simples. L'espace est toujours alloué dans le segment de code

0 votes

Je ne vois pas en quoi le segment de code par rapport au segment de données est vraiment important ici. Je pense que nous avons besoin d'une clarification de la part de l'OP. Il a bien dit "et initialisé, le cas échéant".

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