2010-11-20 13 views
10

Ostatnio gdy byłem tłumacząc podstawową różnicę między wskaźniki i referencje (w kontekście C++ programowanie) z kimś, powiedziałem zwykłych wyjaśnień, które mówią o różnych konwencjach mijających argumentem funkcji - wywołanie przez wartość, Wywołanie przez wskaźnik, Wywołanie przez odniesienie i wszystkie powiązane teorie dotyczące odniesień.C++ referencyjne i const wskaźniki w C/C++

Ale wtedy pomyślałem, że niezależnie od tego, co robi odniesienie C + pod względem przekazywania argumentów, (pozwala na efektywne wykorzystanie pamięci przez duże struktury/obiekty, w tym samym czasie zachowuje bezpieczeństwo, nie pozwalając użytkownikowi zmodyfikować żadnych zmiennych obiektu przekazywane jako odniesienie, jeśli nasz projekt tego wymaga)

const wskaźnik w C będzie osiągnąć to samo, na przykład Jeśli trzeba przekazać wskaźnik struktury powiedzieć struct mystr * ptr, oddając wskaźnik struktury jako stałej -

func(int,int,(const struct mystr*)(ptr)); 

nie PTR być jakiś odpowiednik odniesienia?

  1. Będzie ona działać w sposób, który byłby pamięć wydajny przez nie replikowania struktury (przesuń przez wskaźnik), ale również bezpieczne przez zabronienie jakichkolwiek zmian w dziedzinie konstrukcji ze względu na fakt, że jest ona przekazywana jako wskaźnik const.

    w C++ kontekście obiektu, możemy przekazać obiekt const wskaźnik zamiast odniesienia do obiektu, jak osiągnąć tę samą funkcjonalność)

  2. Jeśli tak, to scenariusz co use-case w C++, potrzebuje referencji. Jakiekolwiek szczególne korzyści z odniesienia, oraz związane z nimi niedogodności?

dziękuję.

-AD

+3

@elusive: W jaki sposób wskaźniki są mniej "bezpieczne dla typu" niż odniesienia? – fredoverflow

Odpowiedz

3

Istnieją dwa typowe scenariusze przypadków użycia:

pierwszy: Wskaźniki oznaczających opcjonalne argumenty. Ponieważ referencje nie mogą być NULL, ale wskaźniki mogą dokument w stylu kodowania, że ​​każdy argument, że jest zanotowana jako wskaźnik można NULL, funkcja musi sobie z tym poradzić. Opcjonalne argumenty mogą być wtedy const lub const, tak samo jak argumenty obowiązkowe (referencyjne).

drugie: Referencje są używane tylko w połączeniu z const słowo kluczowe, ponieważ składnia wywołujący sugeruje czytelnikowi przejść przez wartość semantyki, która jest z definicji stałej.Następnie wskaźniki są używane tylko dla argumentów, które mogą być zmienione przez wywoływacza.

Ja osobiście wolę pierwszą opcję, ponieważ tam każdy z czterech przypadków "const reference", "non const reference", "const pointer", "non const viewer" ma inne znaczenie. Opcja druga rozróżnia tylko dwie "rzeczy": "funkcja może modyfikować tę wartość", a "funkcja nie zmieni tej wartości".

+2

Nie zgadzam się z tym, że "funkcje, które pobierają wskaźniki, muszą zawsze sprawdzać wartość zerową" - jeśli ktoś podaje ci wskaźnik zerowy, jest to zwykle wynikiem poważnego błędu programowania, a awaria jest najbardziej sensowną rzeczą. Jeśli masz parametry, które są naprawdę opcjonalne, jest to znak, że powinieneś po prostu mieć inną, przeciążoną funkcję, lub powinieneś wyodrębnić obiekt metody. –

+0

@Billy ONeal: W tym modelu (który nie został wymyślony w locie przeze mnie) program piszący musi upewnić się, że wskazuje on tylko te argumenty jako wskaźniki, w których podanie 'NULL' w rzeczywistości nie jest poważnym błędem programowania. Głupi przykład: chcesz się zalogować, podaj niezalogowany program rejestrujący do tej funkcji. Mniej głupi (ale biblioteka C) przykład: [sigprocmask] (http://www.kernel.org/doc/man-pages/online/pages/man2/sigprocmask.2.html). W przypadku błędu podania "NULL" funkcja powinna najpierw odwoływać się do referencji. Tak, to oznacza, że ​​większość funkcji przyjmuje tylko odniesienia (lub według wartości, jeśli jest to stosowne). – dennycrane

17

Można powiązać const odniesienia do rvalue:

void foo(const std::string& s); 

foo(std::string("hello")); 

Ale to jest niemożliwe, aby przekazać adres rvalue:

void bar(const std::string* s); 

bar(&std::string("hello")); // error: & operator requires lvalue 

Referencje zostały wprowadzone do język wspierający przeciążanie operatora. Chcesz być w stanie powiedzieć a - b nie &a - &b. (Zauważ, że ten ostatni ma już znaczenia. Wskaźnik odejmowanie)

Referencje przede wszystkim wspierać podanie przez odniesienie, wskaźniki przede wszystkim wspierać semantykę referencyjnych. Tak, wiem, rozróżnienie nie zawsze jest całkiem jasne w C++.

+0

Zdobądź swój punkt, ale przeważnie można by podać referencję do obiektu/zmiennej., Która byłaby w istocie zmienną, a nie stałą, więc w takim przypadku ... – goldenmean

+6

@gold: Ah, mówisz o nie- odwołania do stałych. Tak, w tym przypadku jedyną praktyczną różnicą, jaką widzę (poza wygodą notacji) jest fakt, że nie ma czegoś takiego jak referencja "zerowa". Więc jeśli 'null' jest poprawną opcją, użyj wskaźnika, w przeciwnym razie użyj odniesienia. – fredoverflow

0

W odniesieniu do obiektu odniesienia, jaki kod może manipulować, biorąc pod uwagę odniesienie do const, jest taki sam, jak można zrobić ze wskaźnikiem do obiektu const, i podobnie to, co można nim manipulować, biorąc pod uwagę niezwiązane odniesienie jest takie samo jako podany wskaźnik do obiektu niestałego.

To, co odniesienie uniemożliwia wywołanej funkcji, to zmiana, do którego obiektu odnosi się odniesienie, lub arytmetyczna wskazówka na referencji.

Jeśli chodzi o wywołującego, odwołanie do stałej może być powiązane bezpośrednio z wartością rwartową, a podczas tworzenia i niszczenia obiektów przekazywanych jako argumenty mamy dobrze zdefiniowaną semantykę. Jest to wspólny idiom - zbudować tymczasowy dla argumentu:

// declaration 
void bar (const Foo&); 

// use 
bar (Foo()); 

Nie jest jednak oczywiste, że obiekt Foo w nich ma żywotność, która przekracza długość wywołania funkcji:

// declaration 
void bar (const Foo*); 

// use 
Foo temp; 
bar (&temp); 

// cast to avoid warning about taking address of temporary 
bar (&static_cast<const Foo&>(Foo())); 

// helper function to same effect 
template<typename T> const T* address_of (const T& t) { return &t; } 

bar (address_of (Foo())); 

Chociaż oczywiście to drugie, będąc jedynie wywołaniem funkcji, powinno to uczynić oczywistym.

Zasadniczo referencje to cukier syntaktyczny dla wskaźników wskazujących pojedyncze obiekty, a nie na początku tablic.

+0

Myślę, że myliłeś "wskaźnik const" z "wskaźnikiem do const". –

+0

@ Fix teraz. –

+0

Świetnie! Ale pytanie mogło właściwie oznaczać to, co napisano: "wskaźnik const" (jak referencja, to nie może być odbicie) zamiast "wskaźnik do const". –