39 votes

Comment les références sont-elles mises en œuvre en interne ?

Je me demande juste comment les références sont réellement implémentées sur différents compilateurs et configurations de débogage/publication. La norme fournit-elle des recommandations sur leur mise en œuvre ? Les implémentations diffèrent-elles ?

J'ai essayé d'exécuter un programme simple où je renvoie des références non-const et des pointeurs vers des variables locales à partir de fonctions, mais elles ont fonctionné de la même manière. Cela signifie-t-il que les références ne sont en interne qu'un pointeur ?

49voto

IfLoop Points 59461

Juste pour répéter certains des trucs que tout le monde a dit, regardons la sortie du compilateur :

#include <stdio.h>
#include <stdlib.h>

int byref(int & foo)
{
  printf("%d\n", foo);
}
int byptr(int * foo)
{
  printf("%d\n", *foo);
}

int main(int argc, char **argv) {
  int aFoo = 5; 
  byref(aFoo);
  byptr(&aFoo);
}

Nous pouvons compiler cela avec LLVM (avec les optimisations désactivées) et nous obtenons ce qui suit :

define i32 @_Z5byrefRi(i32* %foo) {
entry:
  %foo_addr = alloca i32*                         ; <i32**> [#uses=2]
  %retval = alloca i32                            ; <i32*> [#uses=1]
  %"alloca point" = bitcast i32 0 to i32          ; <i32> [#uses=0]
  store i32* %foo, i32** %foo_addr
  %0 = load i32** %foo_addr, align 8              ; <i32*> [#uses=1]
  %1 = load i32* %0, align 4                      ; <i32> [#uses=1]
  %2 = call i32 (i8*, ...)* @printf(i8* noalias getelementptr inbounds ([4 x i8]* @.str, i64 0, i64 0), i32 %1) ; <i32> [#uses=0]
  br label %return

return:                                           ; preds = %entry
  %retval1 = load i32* %retval                    ; <i32> [#uses=1]
  ret i32 %retval1
}

define i32 @_Z5byptrPi(i32* %foo) {
entry:
  %foo_addr = alloca i32*                         ; <i32**> [#uses=2]
  %retval = alloca i32                            ; <i32*> [#uses=1]
  %"alloca point" = bitcast i32 0 to i32          ; <i32> [#uses=0]
  store i32* %foo, i32** %foo_addr
  %0 = load i32** %foo_addr, align 8              ; <i32*> [#uses=1]
  %1 = load i32* %0, align 4                      ; <i32> [#uses=1]
  %2 = call i32 (i8*, ...)* @printf(i8* noalias getelementptr inbounds ([4 x i8]* @.str, i64 0, i64 0), i32 %1) ; <i32> [#uses=0]
  br label %return

return:                                           ; preds = %entry
  %retval1 = load i32* %retval                    ; <i32> [#uses=1]
  ret i32 %retval1
}

Les corps des deux fonctions sont identiques

17voto

Peter G. Points 8566

La mise en œuvre naturelle d'une référence est en effet un indicateur. Cependant, ne dépendez pas de cela dans votre code.

2voto

kamerunka Points 106

Il n'y a pas besoin d'une référence pour être un pointeur. Dans de nombreux cas, c'est le cas, mais dans d'autres cas, c'est juste un alias et il n'y a pas besoin d'allocation de mémoire séparée pour un pointeur. Les échantillons d'assemblage ne sont pas toujours corrects, car ils dépendent fortement des optimisations et de la façon dont "intelligent" est le compilateur.

par exemple : int i ; int& j = i ;

n'a pas besoin de générer de code supplémentaire ou d'allouer de mémoire supplémentaire.

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