Czy są korzyści z przechodzenia przez wskaźnik nad przechodzeniem przez odniesienie w C++?

Jakie są korzyści z przechodzenia przez wskaźnik nad przechodzeniem przez odniesienie w C++?

Ostatnio widziałem wiele przykładów, które wybrały przekazywanie argumentów funkcji za pomocą wskaźników zamiast przekazywania przez odniesienie. Czy robienie tego przynosi korzyści?

Przykład:

func(SPRITE *x);

Z wywołaniem

func(&mySprite);

Vs.

func(SPRITE &x);

Z wywołaniem

func(mySprite);
Author: Sobi, 2008-12-02

6 answers

Wskaźnik może otrzymać parametr NULL, parametr referencyjny Nie. Jeśli istnieje szansa, że chcesz przekazać "brak obiektu", użyj wskaźnika zamiast odniesienia.

Ponadto, przechodzenie przez wskaźnik pozwala jawnie zobaczyć w miejscu wywołania, czy obiekt jest przekazywany przez wartość, czy przez odniesienie:

// Is mySprite passed by value or by reference?  You can't tell 
// without looking at the definition of func()
func(mySprite);

// func2 passes "by pointer" - no need to look up function definition
func2(&mySprite);
 203
Author: Adam Rosenfield,
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
2012-11-14 16:01:36

Przechodzenie przez wskaźnik

  • rozmówca musi przyjąć adres - > nie przezroczysty
  • można podać wartość 0 oznaczającą nothing. Może to być użyte do podania opcjonalnych argumentów.

Pass by reference

  • wywołujący po prostu przechodzi przez obiekt - > przezroczysty. Musi być używany do przeciążania operatorów, ponieważ przeciążanie typów wskaźników nie jest możliwe (wskaźniki są typami wbudowanymi). Więc nie możesz zrobić {[1] } używając wskaźników.
  • Brak wartości 0 - > wywołane funkcja nie musi ich sprawdzać
  • odniesienie do const akceptuje również tymczasowe: void f(const T& t); ... f(T(a, b, c));, wskaźniki nie mogą być używane w ten sposób, ponieważ nie można przyjąć adresu tymczasowego.
  • wreszcie, referencje są łatwiejsze w użyciu - > mniejsza szansa na błędy.
 224
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
2008-12-02 18:00:26

Allen Holub 's" Enough Rope to Shoot Yourself in the Foot " wymienia następujące 2 Zasady:

120. Reference arguments should always be `const`
121. Never use references as outputs, use pointers

Wymienia kilka powodów, dla których odniesienia zostały dodane do C++:

  • są niezbędne do zdefiniowania konstruktorów kopiujących
  • są niezbędne do przeciążenia operatora
  • const referencje pozwalają mieć semantykę pass-by-value, unikając kopii

Jego głównym punktem jest to, że odniesienia nie powinny być używane jako parametry "wyjściowe", ponieważ w miejscu wywołania nie ma wskazania, czy parametr jest parametrem odniesienia czy wartości. Tak więc jego regułą jest używanie tylko referencji const jako argumentów.

Osobiście uważam, że jest to dobra zasada, ponieważ wyjaśnia, kiedy parametr jest parametrem wyjściowym, czy nie. Jednak, podczas gdy ja osobiście zgadzam się z tym w ogóle, pozwalam sobie być kołysany przez opinie innych z mojego zespołu, jeśli kłócą się o parametry wyjściowe jako odniesienia (niektórzy deweloperzy lubią je ogromnie).

 56
Author: Michael Burr,
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
2008-12-02 18:26:03

Podoba mi się rozumowanie artykułu z "cplusplus.com:"

  1. Przekazuje wartość, gdy funkcja nie chce modyfikować parametru, a wartość jest łatwa do skopiowania (ints, doubles, char, bool, itd... proste typy. std::string, std:: vector i wszystkie inne kontenery STL nie są prostymi typami.)

  2. Przechodzi przez wskaźnik const, gdy wartość jest kosztowna do skopiowania i funkcja nie chce modyfikować wskazywanej wartości, a NULL jest poprawną, oczekiwaną wartością że funkcja obsługuje.

  3. Przechodzi przez wskaźnik non-const, gdy wartość jest kosztowna do skopiowania i funkcja chce zmodyfikować wskazywaną wartość, a NULL jest poprawną, oczekiwaną wartością, którą obsługuje funkcja.

  4. Przekazuje referencję const, gdy wartość jest kosztowna do skopiowania, a funkcja nie chce modyfikować wartości, o której mowa, a NULL nie byłaby prawidłową wartością, gdyby zamiast niej użyto wskaźnika.

  5. Przejść przez odniesienie non-cont, gdy wartość jest kosztowna w kopiowaniu i funkcja chce zmodyfikować wartość, o której mowa, a NULL nie byłaby poprawną wartością, gdyby zamiast niej użyto wskaźnika.

  6. Podczas pisania funkcji szablonowych nie ma jednoznacznej odpowiedzi, ponieważ istnieje kilka kompromisów, które wykraczają poza zakres tej dyskusji, ale wystarczy powiedzieć, że większość funkcji szablonowych przyjmuje swoje parametry według wartości lub (const) odniesienia, jednak ponieważ składnia iteratora jest podobna do składni wskaźników (gwiazdka do "dereference"), każda funkcja szablonu, która oczekuje iteratorów jako argumentów, Domyślnie również akceptuje wskaźniki (i nie sprawdza, czy nie ma NULL, ponieważ koncepcja iteratora NULL ma inną składnię).

Http://www.cplusplus.com/articles/z6vU7k9E/

Z tego wynika, że główną różnicą między wyborem wskaźnika lub parametru referencyjnego jest to, czy NULL jest wartością akceptowalną. To wszystko.

Czy wartość jest wejście, wyjście, modyfikowanie itp. w końcu powinno być w dokumentacji / komentarzach dotyczących funkcji.

 51
Author: R. Navega,
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
2016-12-20 19:12:48

Wyjaśnienia do poprzednich postów:


Referencje są a nie gwarancją uzyskania wskaźnika non-null. (Choć często traktujemy je jako takie.)

Podczas gdy straszliwie zły kod, jak w take you out behind the woodshed bad code, następujący kod będzie kompilował i uruchamiał: (przynajmniej pod moim kompilatorem.)

bool test( int & a)
{
  return (&a) == (int *) NULL;
}

int
main()
{
  int * i = (int *)NULL;
  cout << ( test(*i) ) << endl;
};

Prawdziwy problem z referencjami leży u innych programistów, odtąd określanych idioci, którzy przydzielają w konstruktor, deallocate w destruktorze, i nie dostarczy konstruktora kopiującego lub operatora=().

Nagle jest świat różnicy między foo (BAR bar) i foo (BAR & bar) . (Wywoływana jest automatyczna operacja kopiowania bitowego. Dealokacja w destruktorze jest wywoływana dwukrotnie.)

Na szczęście nowoczesne Kompilatory wychwycą tę podwójną dealokację tego samego wskaźnika. 15 lat temu nie. (Pod gcc/g++, użyj setenv MALLOC_CHECK_ 0 aby powrócić do starych sposobów.), W wyniku czego, pod DEC UNIX, ta sama pamięć jest przydzielana do dwóch różnych obiektów. Dużo zabawy z debugowaniem...


Bardziej praktycznie:

  • Referencje ukrywają, że zmieniasz dane przechowywane gdzie indziej.
  • łatwo pomylić Odniesienie z skopiowanym obiektem.
  • wskaźniki sprawiają, że to oczywiste!
 6
Author: Mr.Ree,
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
2008-12-03 00:22:36

Niezupełnie. Wewnętrznie przekazywanie przez odniesienie odbywa się poprzez zasadniczo przekazanie adresu obiektu odniesienia. Tak więc naprawdę nie ma żadnych zysków wydajności, które można uzyskać, przekazując wskaźnik.

Przechodzenie przez odniesienie ma jednak jedną korzyść. Masz gwarancję wystąpienia dowolnego obiektu/typu, który jest przekazywany. Jeśli zdasz wskaźnik, ryzykujesz otrzymanie wskaźnika NULL. Używając pass-by-reference, naciskasz na niejawne NULL-sprawdź jeden poziom do rozmówcy swojej funkcji.

 3
Author: Brian,
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
2008-12-02 18:03:10