różnica między wskaźnikiem a parametrem referencyjnym?

Czy to to samo:

int foo(bar* p) {
  return p->someInt();
}

I

int foo(bar& r) {
  return r.someInt();
}

Ignoruj potencjał wskaźnika null. Czy te dwie funkcje są funkcjonalnie identyczne bez względu na to, czy someInt() są wirtualne, czy są przekazywane bar lub podklasa bar?

Czy ten kawałek cokolwiek:

bar& ref = *ptr_to_bar;
Author: Artjom B., 2009-03-07

8 answers

Odniesienia do C++ nie są celowo określone w standardzie, który ma być zaimplementowany za pomocą wskaźników. Odniesienie jest bardziej "synonimem" zmiennej niż wskaźnikiem do niej. Ta semantyka otwiera pewne możliwe optymalizacje dla kompilatora, gdy możliwe jest uświadomienie sobie, że wskaźnik byłby przesadą w niektórych sytuacjach.

Jeszcze kilka różnic:

  • nie można przypisać NULL Do referencji. Jest to zasadnicza różnica i główny powód, dla którego wolisz jeden niż na inne.
  • Kiedy przyjmiesz adres pointer, dostajesz adres zmienna wskaźnika. Kiedy bierzesz adres referencji, otrzymasz adres zmiennej jest / align = "left" /
  • Nie możesz przypisać referencji. Po zainicjowaniu wskazuje na ten sam obiekt przez całe swoje życie.
 61
Author: shoosh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-21 08:49:36

Ignorowanie wszystkich cukrów składniowych i możliwości, które można zrobić z jednym, a nie z drugim oraz różnic między wskaźnikami i odniesieniami wyjaśnionych w innych odpowiedziach (na inne pytania) ... Tak, te dwa są funkcjonalnie dokładnie takie same! Oba wywołują funkcję i obie obsługują funkcje wirtualne równie dobrze.

I nie, twoja linia się nie tnie. To tylko powiązanie odniesienia bezpośrednio z obiektem wskazywanym przez wskaźnik.

Kilka pytań dlaczego chcesz użyć jednego nad drugim:

Zamiast próbować samemu wymyślić różnice, deleguję Cię do tych, Jeśli chcesz wiedzieć.

 14
Author: Johannes Schaub - litb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:31

Odniesienie jest stałym wskaźnikiem, tzn. nie można zmienić odniesienia na odniesienie do innego obiektu. W przypadku zmiany zmienia się wartość obiektu odsyłającego.

Dla Ex:

       int j = 10;
       int &i = j;
       int l = 20;
       i = l; // Now value of j = 20

       int *k = &j;
       k = &l;   // Value of j is still 10
 11
Author: Vinay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-07 05:30:41

Tak są funkcjonalnie identyczne. Ponieważ odwołanie będzie wymagało ustawienia go na obiekt przed użyciem, nie będziesz musiał radzić sobie ze wskaźnikami null lub wskaźnikami do nieprawidłowej pamięci.

Ważne jest również, aby zobaczyć różnicę semantyczną:

  • Użyj referencji, gdy chcesz przekazać obiekt normalny-ale jest on tak duży , że bardziej sensowne jest przekazywanie referencji do obiektu, a nie robienie kopii (jeśli nie modyfikujesz obiektu, który jest).
  • użyj wskaźnika, gdy chcesz radzić sobie z adresem pamięci, a nie z obiektem.
 5
Author: Patrick Glandien,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-06 22:19:24

Nie używałem C++ przez długi czas, więc nawet nie zamierzam próbować naprawdę odpowiedzieć na twoje pytanie (przepraszam); jednak Eric Lippert właśnie opublikował doskonały artykuł o wskaźnikach / odniesieniach, które pomyślałem, że wskażę ci.

 4
Author: Chris Shaffer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-06 22:11:42

Nie wiem, czy ktoś odpowiedział na twoje drugie pytanie Ukryte na dole o krojeniu... nie, to nie spowoduje krojenia.

Slicing jest wtedy, gdy obiekt Pochodny jest przypisany (kopiowany) do obiektu klasy bazowej -- specjalizacja klasy pochodnej jest "odcinana". Zauważ, że powiedziałem, że obiekt jest kopiowany, nie mówimy o wskaźnikach kopiowanych/przypisywanych, ale o samych obiektach.

W twoim przykładzie tak się nie dzieje. Po prostu odsyłasz wskaźnik do paska obiekt (w wyniku czego powstaje obiekt Bar) używany jako wartość R w inicjalizacji odniesienia. Nie jestem pewien, czy dobrze zrozumiałam terminologię...

 4
Author: Dan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-07 02:40:29

Jak wszyscy inni wspominali, w implementacji odniesienia i wskaźniki są w dużej mierze takie same. Są pewne drobne zastrzeżenia:

  • Nie można przypisać NULL Do referencji (shoosh wspomniał o tym): to znaczące, ponieważ nie ma "undefined "lub" invalid " reference wartość.

  • Możesz zdać tymczasowy zmienna jako odniesienie const , ale podanie wskaźnika nie jest legalne do tymczasowego.

Na przykład, jest to ok:

class Thingy; // assume a constructor Thingy(int,int)
void foo(const Thingy &a)
{ 
   a.DoSomething();
}

void bar( ) 
{
  foo( Thingy(1,2) );
}

Ale większość kompilatorów narzeka na

void foo2( Thingy * a);

void bar2()
{
  foo( &Thingy(1,2) );
}
  • pobranie adresu zmiennej w celu uzyskania wskaźnika wymusza na kompilatorze zapisanie go w pamięci. Przypisanie odniesienia do zmiennej lokalnej tworzy tylko synonim; w niektórych przypadkach może to pozwolić kompilatorowi na przechowywanie danych w rejestrze i uniknięcie load-hit-store . Jednak dotyczy to tylko zmiennych lokalnych - gdy coś jest przekazywane jako parametr przez odniesienie, nie można uniknąć zapisania go do stack.

 

void foo()
{
   int a = 5;
   // this may be slightly more efficient
   int &b = a;
   printf( "%d", ++b );
   // than this
   int *c = &a;
   printf( "%d", ++(*c) );
}
  • Podobnie, słowo kluczowe __restrict nie może być stosowane do referencji, tylko do wskaźników.

  • Nie możesz arytmetyki wskaźników z referencjami, więc jeśli masz wskaźnik do tablicy, to następny element w tablicy może być przez p+1, odniesienie zawsze wskazuje tylko jedną rzecz w całym swoim życiu.

 3
Author: Crashworks,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-06 22:46:16

Funkcje oczywiście nie są "takie same", ale jeśli chodzi o zachowanie wirtualne, będą zachowywać się podobnie. Jeśli chodzi o krojenie, dzieje się tak tylko wtedy, gdy masz do czynienia z wartościami, a nie referencjami lub wskaźnikami.

 1
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-06 22:16:39