78 votes

Ne const-correctness donner le compilateur plus de place pour l'optimisation?

Je sais que cela améliore la lisibilité et rend le programme de moins d'erreur, mais combien faut-il d'améliorer les performances?

Et sur une note de côté, quelle est la différence majeure entre une référence et un const pointeur? Je suppose qu'ils sont stockés dans la mémoire différemment, mais comment?

Merci.

70voto

Nemo Points 32838

[Edit: OK, donc cette question est plus subtile que ce que je pensais au premier abord.]

Déclaration d'un pointeur vers const ou de référence-de-const n'aide jamais un compilateur d'optimiser quoi que ce soit. (Bien que de voir la mise à Jour au bas de cette réponse.)

L' const déclaration indique seulement comment un identifiant sera utilisé à l'intérieur de la portée de sa déclaration; il ne dit pas que l'objet sous-jacent ne peut pas le changer.

Exemple:

int foo(const int *p) {
    int x = *p;
    bar(x);
    x = *p;
    return x;
}

Le compilateur ne peut pas supposer qu' *p n'est pas modifié par l'appel à l' bar()car p pourrait être (par exemple) un pointeur vers un mondial int et bar() pourra la modifier.

Si le compilateur sait assez sur l'appelant de foo() et le contenu de bar() qu'il peut prouver bar() ne modifie pas *p, alors il peut aussi réaliser que la preuve sans le const déclaration.

Mais c'est vrai en général. Parce qu' const seulement a un effet dans le champ d'application de la déclaration, le compilateur peut déjà voir comment vous traitez le pointeur ou une référence dans cette étendue; il sait déjà que vous n'êtes pas la modification de l'objet sous-jacent.

Donc, en bref, tous const t dans ce contexte est de vous empêcher de faire des erreurs. Il n'a pas d'indiquer au compilateur tout ce qu'il ne connaissent pas déjà, et par conséquent, il n'est pas pertinent pour l'optimisation.

Quid des fonctions qui appellent foo()? Comme:

int x = 37;
foo(&x);
printf("%d\n", x);

Le compilateur prouver que cela s'imprime 37, depuis foo() prend un const int *?

Pas de. Même si foo() prend un pointeur-à-const, cela pourrait jeter la const-ness loin et modifier le type int. (C'est pas un comportement non défini.) Ici encore, le compilateur ne peut pas faire d'hypothèses en général; et si elle en sait assez sur foo() de faire une telle optimisation, il va savoir que, même sans le const.

La seule fois const pourrait permettre des optimisations est des cas comme ceci:

const int x = 37;
foo(&x);
printf("%d\n", x);

Ici, à modifier x par quelque mécanisme que ce soit (par exemple, en prenant un pointeur et jetant l' const) est d'invoquer un Comportement Indéfini. Ainsi, le compilateur est libre de penser que vous ne le faites pas, et il peut se propager à la constante de 37 dans le printf(). Ce type d'optimisation est légal pour n'importe quel objet vous déclarez const. (Dans la pratique, une variable locale à laquelle vous ne prenez jamais de référence ne sera pas en bénéficier, car le compilateur ne peut déjà voir si vous les modifiez dans son champ d'application.)

Pour répondre à votre "note de côté" de la question, (un) const pointeur est un pointeur; et (b) un pointeur const peut être égal à NULL. Il est exact que la représentation interne (c'est à dire une adresse) est probablement la même.

[mise à jour]

Comme Christoph points dans les commentaires, ma réponse est incomplète car elle ne fait pas mention d' restrict.

Section 6.7.3.1 (4) de la standard C99 dit:

Lors de chaque exécution de B, soit L tout lvalue qui a &L selon P. Si L est utilisé pour accéder à la valeur de l'objet X qu'il désigne, et X est également modifiée (par tous moyens), les exigences suivantes s'appliquent: T ne sera pas const-qualifiés. ...

(Ici B est un bloc de base sur laquelle P, restreindre l'-pointeur-de-T, est dans le domaine.)

Donc, si une fonction C foo() est déclaré comme ceci:

foo(const int * restrict p)

...puis le compilateur peut supposer que l'absence de modification de *p se produisent au cours de la durée de vie d' p -- c'est à dire, lors de l'exécution de l' foo() -- parce que sinon, le Comportement est Indéfini.

Donc, en principe, combinant restrict avec un pointeur-à-const pourrait permettre à la fois de les optimisations qui sont licenciés ci-dessus. Ne les compilateurs de mettre en œuvre une telle optimisation, je me demande? (GCC 4.5.2, au moins, ne l'est pas.)

Notez que restrict n'existe que dans C, pas du C++ (même pas de C++0x), sauf un compilateur spécifique de l'extension.

7voto

Christoph Points 64389

Sur le dessus de ma tête, je pense à deux cas où en const-qualification permet des optimisations supplémentaires (dans le cas où l'ensemble de l'analyse du programme n'est pas disponible):

const int foo = 42;
bar(&foo);
printf("%i", foo);

Ici, le compilateur sait imprimer 42 sans avoir à examiner le corps de l' bar() (ce qui pourrait ne pas être visible dans le courant de l'unité de traduction) parce que toutes les modifications apportées à l' foo sont illégaux (c'est la même que la Nemo exemple).

Cependant, cela est également possible sans marquage foo comme const en déclarant bar() comme

extern void bar(const int *restrict p);

Dans de nombreux cas, le programmeur veut réellement restrict-qualifiés pointeurs - -const , et non de la plaine des pointeurs - -const que les paramètres de la fonction, que seuls les anciens font aucune garantie quant à la mutabilité de la pointe-aux objets.

Quant à la deuxième partie de votre question: à toutes fins pratiques, une référence C++ peut être considéré comme un pointeur constant (et non pas un pointeur vers une valeur constante!) avec automatique indirection il n'est "plus sûr" ou "plus vite" qu'un pointeur, plus pratique.

6voto

Matthieu M. Points 101624

Il y a deux problèmes avec const en C++ (pour autant que l'optimisation est concerné):

  • const_cast
  • mutable

const_cast signifie que même si vous passez un objet par référence const ou const pointeur, la fonction pourrait jeter la const-ness loin et modifier l'objet (autorisée si l'objet n'est pas const pour commencer).

mutable signifie que même si un objet est - const, certaines de ses parties peuvent être modifiés (comportement de mise en cache). Aussi, les objets pointés (au lieu d'être la propriété) peut être modifié en const méthodes, même quand ils sont logiquement partie de l'état de l'objet. Et enfin les variables globales peuvent être modifiés aussi...

const est là pour aider le développeur à attraper logique des erreurs au début.

4voto

servn Points 2581

const-correctness ne pas aider à la performance; la plupart des compilateurs n'ont même pas pris la peine de suivre constness au-delà de l'interface. Le marquage des variables const peut vous aider, en fonction de la situation.

Les références et les pointeurs sont stockées exactement de la même manière dans la mémoire.

2voto

Mankarse Points 22800

Cela dépend vraiment du compilateur/plate-forme (il peut aider à l'optimisation sur certains compilateur qui n'a pas encore été écrite, ou sur quelque plate-forme que vous n'utilisez jamais). Le C et le C++ normes de rien dire au sujet de la performance autre que de donner à des exigences de complexité pour certaines fonctions.

Les pointeurs et les références à const habitude de ne pas aider à l'optimisation, comme la const de qualification peuvent légalement être jeté dans certaines situations, et il est possible que l'objet peut être modifiée par un autre non-const de référence. D'autre part, de déclarer un objet const peut être utile, car il garantit que l'objet ne peut pas être modifié (même lorsqu'il est passé à des fonctions que le compilateur ne connaît pas la définition de l'). Cela permet au compilateur de stocker les const objet dans la mémoire en lecture seule, ou cache sa valeur dans un endroit centralisé, réduisant la nécessité pour les copies et les contrôles pour les modifications.

Les pointeurs et les références sont généralement mis en œuvre exactement de la même manière, mais encore une fois c'est totalement plate-forme de charge. Si vous êtes vraiment intéressé, alors vous devriez regarder dans le code machine généré pour votre plate-forme et le compilateur dans votre programme (si vous utilisez un compilateur qui génère du code machine).

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