4 votes

Comment le compilateur détermine-t-il la taille de pile nécessaire pour une fonction avec des temporaires générés par le compilateur ?

Considérez le code suivant :

class cFoo {
    private:
        int m1;
        char m2;
    public:
        int doSomething1();
        int doSomething2();
        int doSomething3();
}

class cBar {
    private:
        cFoo mFoo;
    public:
        cFoo getFoo(){ return mFoo; }
}

void some_function_in_the_callstack_hierarchy(cBar aBar) {
    int test1 = aBar.getFoo().doSomething1();
    int test2 = aBar.getFoo().doSomething2();
    ...
}

Dans la ligne où getFoo() est appelé, le compilateur va générer un objet temporaire de cFoo, pour pouvoir appeler doSomething1(). Le compilateur réutilise-t-il la mémoire de la pile qui est utilisée pour ces objets temporaires ? Combien de mémoire de pile l'appel de "some_function_in_the_callstack_hierarchy" va-t-il réserver ? Est-ce qu'il réserve de la mémoire pour chaque objet temporaire généré ?

Je pensais que le compilateur ne réservait de la mémoire que pour un seul objet de cFoo et qu'il réutiliserait la mémoire pour différents appels, mais si j'ajoute

    int test3 = aBar.getFoo().doSomething3();

Je peux voir que la taille de la pile nécessaire pour "some_function_in_the_callstack_hierarchy" est beaucoup plus importante et ce n'est pas seulement à cause de la variable int locale supplémentaire.

Par contre, si i remplace alors

cFoo getFoo(){ return mFoo; }

avec une référence (uniquement à des fins de test, car renvoyer une référence à un membre privé n'est pas bon)

const cFoo& getFoo(){ return mFoo; }

il a besoin de beaucoup moins de mémoire de pile, que la taille d'un cFoo.

Pour moi, il semble donc que le compilateur réserve de la mémoire de pile supplémentaire pour chaque objet temporaire généré dans la fonction. Mais cela serait très inefficace. Quelqu'un peut-il expliquer cela ?

5voto

Basile Starynkevitch Points 67055

Le site compilateur optimisant consiste à transformer votre code source en une représentation interne, et à la normaliser.

Avec logiciel gratuit compilateurs (comme CCG & Clang/LLVM ), vous êtes en mesure de regarder dans cette représentation interne (au moins en Parcheando le code du compilateur ou en l'exécutant dans un débogueur).

D'ailleurs, parfois, les valeurs temporaires n'ont même pas besoin d'espace sur la pile, par exemple parce qu'elles ont été optimisées ou parce qu'elles peuvent être placées dans des registres. Et très souvent, elles réutilisent un emplacement inutile dans le cadre d'appel actuel. De même (particulièrement en C++), de nombreuses (petites) fonctions sont en ligne -comme votre getFoo est probablement- (donc ils n'ont pas de cadre d'appel eux-mêmes). Les GCC récents sont même parfois capable de appel de la queue (essentiellement en réutilisant le cadre d'appel de l'appelant).

Si vous compilez avec GCC (i.e. g++ ) Je vous suggère de jouer avec options d'optimisation y options de développement (et quelques autres). Peut-être utiliser également -Wstack-usage=48 (ou une autre valeur, en octets par trame d'appel) et/ou -fstack-usage

Tout d'abord, si vous pouvez lire le code assembleur, compilez yourcode.cc con g++ -S -fverbose-asm -O yourcode.cc et regarder dans l'émission yourcode.s

(n'oubliez pas de jouer avec les drapeaux d'optimisation, ainsi remplacez -O con -O2 o -O3 ....)

Ensuite, si vous êtes plus curieux de savoir comment le compilateur optimise, essayez g++ -O -fdump-tree-all -c yourcode.cc et vous obtiendrez un grand nombre de "fichiers de vidage" qui contiennent un partiel le rendu textuel des représentations internes pertinentes pour le GCC.

Si vous êtes encore plus curieux, jetez un coup d'oeil à mon GCC MELT et notamment son documentation (qui contient une lot de diapositives et de références).

Pour moi, il semble donc que le compilateur réserve de la mémoire de pile supplémentaire pour chaque objet temporaire généré dans la fonction.

Certainement pas, dans le cas général (et bien sûr en supposant que vous activiez certaines optimisations). Et même si un espace est réservé, il sera très rapidement réutilisé.

BTW : remarquez que la norme C++11 ne parle pas de pile. On pourrait imaginer un programme C++ compilé sans utiliser de pile (par exemple, une optimisation de programme entier détectant un programme sans récursion dont l'espace de pile et la disposition pourraient être optimisés pour éviter toute pile. Je ne connais pas de tel compilateur, mais je sais que les compilateurs peuvent être très intelligents....).

4voto

Bathsheba Points 23209

Tenter d'analyser comment Le traitement par un compilateur d'un morceau de code particulier devient de plus en plus difficile à mesure que les stratégies d'optimisation deviennent plus agressives.

Tout ce qu'un compilateur doit faire, c'est mettre en œuvre la norme C++ et compiler le code sans introduire ni annuler d'effets secondaires (avec quelques exceptions telles que l'optimisation des valeurs de retour et de retour nommé).

Vous pouvez voir dans votre code que, puisque cFoo n'est pas un type polymorphe et n'a pas de données membres, un compilateur pourrait optimiser la création d'un objet et appeler ce qui est essentiellement donc static fonctions directement. J'imagine que même au moment où j'écris ces lignes, certains compilateurs le font déjà. Vous pouvez toujours vérifier l'assemblage de sortie pour être sûr.

Edit : L'OP a maintenant présenté les membres de la classe. Mais comme ceux-ci ne sont jamais initialisés et sont private le compilateur peut les supprimer sans trop y penser. Cette réponse reste donc valable.

1voto

SK-logic Points 6952

La durée de vie d'un objet temporaire s'étend jusqu'à la date de fin de validité de l'objet. fin de l'expression complète contenant voir le paragraphe "12.2 Objets temporaires" de la norme.

Il est très peu probable que, même avec les paramètres d'optimisation les plus bas, un compilateur ne réutilise pas l'espace après la fin de vie d'un objet temporaire.

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