2010-05-30 5 views
17

J'ai lu sur C++ sur Internet, et voici une chose à laquelle je n'ai pas encore trouvé de réponse.Variables statiques dans les fonctions en C++ - allouées même si la fonction ne s'exécute pas?

Je sais que les variables statiques utilisées dans les fonctions s'apparentent à des globales, et que les invocations suivantes de cette fonction verront la variable statique conserver sa valeur entre les appels.

Cependant, si la fonction n'est jamais appelée, la variable statique est-elle allouée?

Merci

+0

C'est une bonne raison de placer des fonctions dans une unité de traduction séparée; de sorte que les fonctions jamais appelées puissent être supprimées au moment de la construction. :-) –

+0

Vous devez faire la distinction entre __allocation__ et __initialization__.Si une fonction non appelée n'est pas supprimée par l'éditeur de liens, il est probable que la mémoire de cette variable soit _allocated_, même si elle n'est jamais _initialized_. – sbi

+0

@Thomas: il y a une bonne raison de choisir un compilateur qui n'a pas besoin de beaucoup de prise en main. Ce n'est pas sorcier de savoir si 'void foo()' est appelé. – MSalters

Répondre

16

Si la fonction est jamais appelée, il est probable que votre éditeur de liens deadstrip la fonction et la variable statique, l'empêchant d'entrer dans .rodata, .data ou .bss segments (ou équivalents de format de fichier exécutable).

Cependant, il existe plusieurs raisons pour lesquelles un éditeur de liens ne peut pas deadstrip (les drapeaux lui disant de ne pas, une incapacité à déterminer ce qui dépend du symbole, etc).

Il est bon de vérifier votre fichier de mappage éditeur de liens (parfois juste un fichier texte!), Ou en utilisant objdump, nm ou dumpbin utilitaires sur l'exécutable pour voir finale si le symbole ou les symboles liés (tels que le code initialiseur statique) ont survécu.

+0

+1 Pour la mention deadstrip et la possibilité que l'éditeur de liens supprime la (les) variable (s) avec la fonction. –

+2

* note: .rodata, .data et .bss sont spécifiques à unix. (mais +1) –

+0

@Billy ONeal: Système V ABI, oui? Je me demande ce que l'histoire de ces segments est ... J'ai supposé qu'ils ont été intégrés dans ELF, mais vous pouvez (et nous le faisons) spécifier des segments personnalisés tout le temps, et le format ELF ne semble pas avoir beaucoup de traitement spécial pour le les plus courants (autres que la définition différente des drapeaux 'SHT_ *', etc.). Quelqu'un at-il une référence pour les sections de fenêtres équivalentes? (Peut-être quelque part dans la documentation de PE/COFF? Temps d'aller creuser ...) – leander

1

Je suis sûr que cela va être à la mise en œuvre. Ce que fait MSVC - les objets statiques sont alloués dans le segment de données automatique de l'EXE ou de la DLL. Cependant, le constructeur n'est exécuté que la première fois que la fonction contenant le static est exécutée.

8

Le C++ Standard, section 6.7 dit:

L'initialisation à zéro (8,5) de tous les objets locaux avec stockage statique durée (3.7.1) est effectuée avant toute autre initialisation a lieu. Un objet local de type POD (3.9) avec durée de stockage statique initialisée avec des expressions constantes est initialisé avant que son bloc ne soit entré pour la première fois. Une mise en œuvre est autorisé à per- première forme initialisation d'autres objets locaux avec la durée de stockage statique dans les mêmes conditions qu'une mise en œuvre est autorisé à initialiser statiquement un objet avec une durée de stockage statique du périmètre de l'espace de noms (3.6.2). Autrement un tel objet est initialisé le le premier contrôle passe par sa déclaration ; un tel objet est considéré initialisé lors de l'achèvement de son initialisation .

Ce qui indique que les objets statiques locaux sont normalement initialisés la première fois que le flux de contrôle les rencontre. Cependant, ils peuvent bien être attribués avant cela - la norme est quelque peu réticente sur ce qu'est réellement le stockage statique, sauf en ce qui concerne les durées de vie des objets statiques.

0

Oui, l'allocation réelle dépend du compilateur, bien que je pense que chaque compilateur réserve juste l'espace dans le segment .static de l'exécutable (ou l'équivalent dans son format de fichier exécutable).
L'initialisation, cependant, n'a lieu que le premier instant où le flux d'exécution rencontre l'objet statique, ce qui est requis par la norme.
Attention, cependant, l'initialisation de global fonctionne de manière différente. Vous pouvez obtenir de très bonnes réponses à presque toutes les questions sur le site C++ FAQ lite. Je suis également friand de "Effective C++" de Scott Meyers.

0

Dépend. Si vous voulez dire, jamais appelé, comme dans, la fonction n'est littéralement jamais invoquée, alors votre compilateur ne va probablement pas l'allouer, ou même mettre dans le code de la fonction. Si, toutefois, vous l'avez rendu dépendant, disons, de l'entrée de l'utilisateur, et que cette entrée de l'utilisateur ne s'est jamais produite, elle sera probablement pré-allouée. Cependant, vous marchez dans un champ de mines ici, et il est préférable de supposer qu'il est toujours créé par le contrôle du temps entre la fonction (s) qui s'y réfèrent.

4

Chaque objet en C++ a deux périodes de temps imbriquées qui y sont associés: durée de stockage et vie. La durée de stockage est la période pendant laquelle la mémoire brute occupée par l'objet est allouée. Durée de vie est la période entre la construction et la destruction d'un objet réel dans cette mémoire. (Pour les objets de construction de type POD, la destruction n'a pas d'importance ou n'est pas applicable, donc leur durée de vie correspond à leur durée de stockage).

Lorsque quelqu'un dit "alloué", ils se réfèrent généralement à durée de stockage. Le langage ne spécifie pas exactement quand la durée de stockage de l'objet commence. Il est suffisant d'exiger que commence à un certain moment avant que commence la vie de l'objet. Pour cette raison, en général, un objet statique défini dans une fonction peut ne jamais commencer sa durée de vie et, théoriquement, sa durée de stockage ne doit pas non plus commencer. Donc, en théorie, peut-être même pas "alloué". En pratique cependant, tous les objets ayant une durée de stockage statique ("globals", statique locale, etc.) sont normalement traités de la même manière: ils reçoivent une quantité de stockage spécifique au début, au démarrage du programme.


Comme une note supplémentaire, si un objet local avec une durée de stockage statique nécessite une initialisation non trivial, cette initialisation est effectuée lorsque le contrôle passe au-dessus de la définition pour la première fois. Ainsi, dans cet exemple

void foo() { 
    static int *p = new int[100]; 
} 

le tableau dynamique ne sera jamais alloué si la fonction n'est jamais appelée. Et il ne sera alloué qu'une seule fois si la fonction est appelée. Cela ne ressemble pas à ce que vous demandez, mais je le mentionne au cas où.

+0

Cela semble être vrai (p ne sera pas initialisé avant le premier appel de la fonction). C'est un peu bizarre: que se passe-t-il si la fonction foo est appelée à partir d'un thread arbitraire? Disons que nous avons 100 threads qui à un moment donné doivent appeler foo ... Quel thread va initialiser p? Ce sera une condition de course. Quoi qu'il en soit, c'est une mauvaise pratique d'utiliser des objets statiques car il est très difficile de les initialiser. – botismarius

0

Les variables statiques définies sur les classes (membres) ou les fonctions ne sont pas allouées dynamiquement sur la pile lors de l'appel de la fonction, comme les variables non statiques. Ils sont alloués dans une autre zone de code générée réservée aux données globales et statiques. Donc, si vous appelez la fonction ou non, instancier des classes qui contiennent des membres statiques ou non, un espace pour leurs données sera de toute façon réservé sur la zone de données du programme.

Questions connexes