logo

Wskaźniki a referencje w C++

Warunek wstępny: Wskaźniki , Bibliografia

C i C++ obsługują wskaźniki, co różni się od większości innych języków programowania, takich jak Java, Python, Ruby, Perl i PHP, ponieważ obsługują one tylko odniesienia. Ale co ciekawe, C++ wraz ze wskaźnikami obsługuje także referencje.



Na pierwszy rzut oka zarówno referencje, jak i wskaźniki są bardzo podobne, ponieważ oba służą do zapewnienia dostępu jednej zmiennej do drugiej. Ponieważ oba zapewniają wiele takich samych możliwości, często nie jest jasne, czym różnią się te mechanizmy. W tym artykule postaram się zilustrować różnice pomiędzy wskaźnikami a referencjami.

Wskaźniki : Wskaźnik to zmienna przechowująca adres pamięci innej zmiennej. Wskaźnik musi zostać wyłuskany za pomocą metody * operatorowi dostępu do lokalizacji pamięci, na którą wskazuje.

Bibliografia : Zmienna referencyjna to alias, czyli inna nazwa już istniejącej zmiennej. Odniesienie, podobnie jak wskaźnik, jest również realizowane poprzez przechowywanie adresu obiektu.
Referencję można traktować jako stały wskaźnik (nie mylić ze wskaźnikiem do stałej wartości!) z automatycznym pośredniczeniem, tj. kompilator zastosuje * operatora dla Ciebie.



int i = 3;   // A pointer to variable i or 'stores the address of i' int *ptr = &i;   // A reference (or alias) for i. int &ref = i;>

Różnice :

1. Inicjalizacja: Wskaźnik można zainicjować w następujący sposób:

int a = 10; int *p = &a; // OR  int *p; p = &a;>

Możemy zadeklarować i zainicjować wskaźnik w tym samym kroku lub w wielu liniach.



2. Będąc w referencjach,

int a = 10; int &p = a; // It is correct // but int &p; p = a; // It is incorrect as we should declare and initialize references at single step>

NOTATKA: Ta różnica może się różnić w zależności od kompilatora. Powyższa różnica dotyczy Turbo IDE.

3. Przeniesienie: Można ponownie przypisać wskaźnik. Ta właściwość jest przydatna do implementacji struktur danych, takich jak lista połączona, drzewo itp. Zobacz następujący przykład:

int a = 5; int b = 6; int *p; p = &a; p = &b;>

4. Z drugiej strony referencji nie można ponownie przypisać i należy ją przypisać podczas inicjalizacji.

int a = 5; int b = 6; int &p = a; int &p = b; // This will throw an error of 'multiple declaration is not allowed'  // However it is valid statement, int &q = p;>

5. Adres pamięci: Wskaźnik ma swój własny adres pamięci i rozmiar na stosie, podczas gdy odwołanie ma ten sam adres pamięci co oryginalna zmienna i nie zajmuje miejsca na stosie.

int &p = a; cout << &p << endl << &a;>

6. Wartość NULL: Wskaźnikowi można bezpośrednio przypisać wartość NULL, podczas gdy referencji nie można. Ograniczenia związane z referencjami (brak wartości NULL, brak ponownego przypisania) zapewniają, że podstawowe operacje nie napotkają sytuacji wyjątkowej.

7. Pośrednie: Możesz mieć wskaźnik do wskaźnika (zwany podwójnym wskaźnikiem) oferujący dodatkowe poziomy pośredniości, podczas gdy odniesienia oferują tylko jeden poziom pośredniości. Na przykład,

In Pointers, int a = 10; int *p; int **q; // It is valid. p = &a; q = &p;  // Whereas in references, int &p = a; int &&q = p; // It is reference to reference, so it is an error>

8. Działania arytmetyczne: Na wskaźnikach można wykonywać różne operacje arytmetyczne, podczas gdy nie ma czegoś takiego jak arytmetyka referencyjna (można jednak wykonywać arytmetykę wskaźników na adresie obiektu wskazywanego przez referencję, jak w &obj + 5).

Tabelaryczna forma różnicy między referencjami i wskaźnikami w C++

Bibliografia Wskaźniki
Przeniesienie Nie można ponownie przypisać zmiennej w Odniesieniu. Zmienną można ponownie przypisać w wskaźnikach.
Adres pamięci Ma ten sam adres co zmienna oryginalna. Wskaźniki mają swój własny adres pamięci.
Praca Odnosi się do innej zmiennej. Przechowuje adres zmiennej.
Wartość zerowa Nie ma wartości null. Może mieć przypisaną wartość null.
Argumenty Do tej zmiennej odwołuje się metoda przekazywania przez wartość. Wskaźnik działa w oparciu o metodę zwaną przekazywaniem przez referencję.

Kiedy używać Co

Wydajność jest dokładnie taka sama, ponieważ referencje są implementowane wewnętrznie jako wskaźniki. Mimo to możesz zachować w pamięci kilka punktów, aby zdecydować, kiedy czego użyć:

  • Skorzystaj z referencji:
    • W parametrach funkcji i typach zwracanych wartości.
  • Użyj wskaźników:
    • Jeśli wymagana jest arytmetyka wskaźników lub przekazanie wskaźnika NULL. Na przykład w przypadku tablic (należy pamiętać, że dostęp do tablicy jest realizowany za pomocą arytmetyki wskaźników).
    • Aby zaimplementować struktury danych, takie jak lista połączona, drzewo itp. oraz ich algorytmy. Dzieje się tak dlatego, że aby wskazać różne komórki, musimy skorzystać z koncepcji wskaźników.

Cytowane w C++ FAQ Lite : Używaj referencji, kiedy możesz, i wskazówek, kiedy musisz. Jeśli nie ma potrzeby ponownego umieszczania danych, referencje są zwykle preferowane zamiast wskaźników. Zwykle oznacza to, że referencje są najbardziej przydatne w publicznym interfejsie klasy. Odniesienia zwykle pojawiają się na skórze obiektu, a wskaźniki wewnątrz.

Wyjątkiem od powyższego jest sytuacja, gdy parametr funkcji lub wartość zwracana wymaga referencji wartowniczej — referencji, która nie odnosi się do obiektu. Zwykle najlepiej jest to zrobić poprzez zwrócenie/pobranie wskaźnika i nadanie wartości nullptr tego specjalnego znaczenia (odniesienia muszą zawsze być aliasami obiektów, a nie wyłuskanym wskaźnikiem zerowym).

Powiązany artykuł:
Kiedy przekazujemy argumenty jako referencje lub wskaźniki?