2016-02-07 1 views
4

Vous ne savez pas si cela a déjà été demandé auparavant. En répondant à this very simple question, je me suis plutôt demandé ce qui suit. Considérez ceci:Existe-t-il une différence de performance pour déclarer une variable volumineuse dans une fonction comme static?

void foo() 
{ 
    int i{}; 
    const ReallyAnyType[] data = { item1, item2, item3, 
     /* many items that may be potentially heavy to recreate, e.g. of class type */ }; 
    /* function code here... */ 
} 

Maintenant en théorie, les variables locales sont recréées chaque fois que le contrôle atteint la fonction, n'est-ce pas? C'est à dire. Regardez int i ci-dessus - il va être recréé sur la pile à coup sûr. Qu'en est-il du tableau ci-dessus? Est-ce qu'un compilateur peut être aussi intelligent que d'optimiser sa création pour se produire une seule fois, ou ai-je besoin d'un modificateur static ici de toute façon? Qu'en est-il si le tableau n'est pas const? (OK, si ce n'est pas const, il est probablement inutile de le créer une seule fois, car une réinitialisation à l'état par défaut peut être nécessaire entre les appels suite aux modifications effectuées pendant l'exécution de la fonction.)

question fondamentale, mais pour une raison quelconque, je réfléchis toujours. En outre, ignorez le "pourquoi voudriez-vous faire ceci" - ceci est juste une question de langue, pas appliquée à un certain problème ou conception de programmation. Je veux dire à la fois C et C++ ici. S'il y a des différences entre les deux concernant cette question, veuillez les décrire.

Répondre

4

Il a deux questions ici, je pense:

  • peut un compilateur optimisez un objet non staticconst être efficacement static afin qu'il soit seulement créé une fois; et

  • Est-ce une attente raisonnable qu'un compilateur donné le fasse.

Je pense que la réponse à la deuxième question est « Non », parce que je ne vois pas le point de faire une énorme quantité d'analyse de flux de contrôle pour sauver le programmeur la peine de taper le mot static. Cependant, j'ai souvent été surpris par les optimisations que les gens passent leur temps à écrire (par opposition aux optimisations sur lesquelles I pense qu'ils devraient travailler :-)). Tout de même, je recommande fortement d'utiliser le mot static si c'est ce que vous vouliez.

Pour la première question, il existe des circonstances dans lesquelles le compilateur pourrait effectuer l'optimisation basée sur la règle «as-if», mais dans quelques cas, cela fonctionnerait. Tout d'abord, si un objet ou sous-objet dans l'initialiseur a un constructeur/destructeur non trivial, alors la construction/destruction est visible, et ce n'est pas un exemple d'élision de la copie. (Ce paragraphe est en C++ seulement, bien sûr.)

La même chose serait vraie si n'importe quel calcul dans la liste d'initialisation avait des effets secondaires visibles.

Et il devrait aller sans dire que si la valeur d'un sous-objet n'est pas constante, le calcul de ce sous-objet devrait être fait sur chaque construction.Si l'objet et tous les sous-objets sont trivialement copiables, tous les calculs de la liste d'initialisation sont constants et le seul coût de construction est celui de la copie d'un modèle dans l'objet, le compilateur ne peut toujours pas effectuer l'optimisation si il y a une chance que les adresses de plus d'une instance en direct de l'objet puissent être simultanément visibles. Par exemple, si la fonction était récursive et que l'adresse de l'objet était utilisée quelque part (difficile à éviter pour un tableau), il y aurait la possibilité de comparer les adresses de deux de ces objets provenant d'invocations récursives différentes de la fonction. Et ils devraient comparer inégale, car ils sont en fait des objets séparés. (Et, maintenant que j'y pense, la fonction n'aurait même pas besoin d'être récursive dans un environnement multithread.)

Donc la charge de la preuve pour un compilateur souhaitant optimiser cet objet dans une seule instance statique est assez haut. Comme je l'ai dit, il se peut qu'un compilateur donné tente d'effectuer cette tâche, mais je ne m'y attendrais absolument pas.

+0

Grande réponse, prend du temps à lire! Donc, juste pour clarifier, un 'const' n'est pas une garantie du tout et je me trompe en le voyant comme presque identique à' const static' dans ce cas? Je suppose que c'est une vraie confusion dans ma tête. – iksemyonov

+0

@iksemyonov: 'const' est juste une promesse de ne pas changer la valeur de l'objet. Cela n'implique même pas que deux instances de l'objet sont identiques. 'const int maintenant [3] = {hour(), minute(), second()};' – rici

2

Le compilateur ferait presque certainement tout ce qui est jugé optimal, mais très probablement il l'aura en mémoire morte et transformera votre variable locale en un pointeur qui pointe vers le tableau en mémoire morte. Cela suppose que votre tableau est équivalent à un type POD (ou une classe composée de types POD, si votre classe fait quelque chose de non-trivial et/ou modifie d'autres choses, le compilateur ne peut en aucun cas faire cette optimisation).

+0

Cela avec le 'const' et sans un' static', non? – iksemyonov

+0

Oui, il faudrait le 'const'. Sans cela, c'est vous décrivez - il faudrait re-générer sur chaque appel en raison de la modification locale possible (sauf peut-être que le compilateur peut déterminer que * pour sûr * vous ne modifiez pas le tableau non-const). –

+0

@JimBuck Cependant, vous avez un type de classe avec des effets secondaires, alors probablement l'objet sera créé à chaque itération de la boucle. – vsoftco