2011-11-13 16 views
5

kontenery STL mają reference i const_referencetypedef, które w wielu przypadkach widziałem (pojemniki bool jest jedynym wyjątkiem mogę myśleć), może być zdefiniowany jako trywialnieJak dokładnie zachowuje się "referencja" typedef?

typedef value_type& reference; 
typedef const value_type& const_reference; 

Co dokładnie jednak , czy są to typy?

Z tego co rozumiem, mają one "zachowywać się jak odniesienia do typu wartości", ale co to dokładnie oznacza?

MSDN mówi, że reference jest:

typu, który stanowi odniesienie do elementu przechowywanego w wektorze.

Co to dokładnie znaczy? Czy muszą przeciążyć określonych operatorów lub mieć określone zachowanie? Jeśli tak, jakie jest wymagane zachowanie?

+2

Nie sądzę, aby ktokolwiek rozumiał to pytanie. Pyta, jaki typ, który nazywa się "referencją", musi zachowywać się jak. Nie jest to typ referencyjny C++ (np. 'Int &'). –

+0

W drugiej chwili myślę, że w ogóle nie rozumiem Q. Typ "referencja" lub "const_reference" zachowuje się jak normalna referencja lub zachowuje się odwołanie do const, dlaczego uważasz, że powinno zachowywać się inaczej? –

+0

@Als: Pytanie dosłownie brzmi: co oznacza "zachowanie jak normalne odniesienie"? To osobliwe zdanie samo w sobie, więc nie wiem, jakie warunki musiałbym spełnić, zanim mój typ "zachowa się jak normalne odniesienie" (na przykład gdy robiłem pojemnik). – Mehrdad

Odpowiedz

1

co pytasz jest „zawsze mogę nieprawidłowego odniesienia? I tak, można. Oznacza to, że dereferencjonowane reference może zrobić wszystko dereferencjonowane value_type& może zrobić wszystko co jest value_type może zrobić. Jeśli to ma sens dla Ciebie.


nie można przeciążać operatorów na typedefs. typedefs mają takie samo zachowanie jako typ one przypisany. Powodem są one typedef'd jest, aby były mniej uciążliwe i stanowią wspólny „interfejs”

Powodem jest reference jest aby zapobiec rzeczy tak:

template<typename T> 
struct foo { 
    T& bar(); 

    typedef T& reference; 
    reference baz(); 
} 

foo<int> x; 
foo<int>::T& y = x.bar(); // error! returns a T& but I can't create one! 
foo<int>::reference z = x.baz(); // ok! 

To również sprawia, czystsze interfejs i pozwala na korzystanie z SFINAE:

template<typename T> 
typename T::reference second(T::reference& t) { return t.at(1); }; 

template<typename T> 
T& second(T& t) { return t[1]; }; 

std::vector v(10); 
foo f(10); // type with [] overloaded but no reference typedef 
second(x) = 5; // calls first def 
second(f) = 3; // calls second def 
+1

Przepraszam, ale myślę, że przegapiłeś to pytanie. Pytałem, jakie operatory/funkcje musi obsługiwać typ "referencyjny" ... nie wiem, czy mogę przeciążyć, co tam jest ... Już wiem, jak działa 'typedef' i dlaczego wprowadzili abstrakcję itp .; Chciałbym tylko wiedzieć, co "referencja" musi spełniać zgodnie ze standardem. – Mehrdad

+0

@Mehrdad 'reference' może zrobić wszystko, co' value_type & 'może zrobić, co jest wszystkim, co' value_type' może zrobić. – Pubby

+1

Więc jaki jest sens używania 'referencji', kiedy możesz po prostu użyć' value_type & ', jeśli są one tym samym? Tam * ma * być zbiorem koniecznych i wystarczających warunków, które muszą spełniać "odniesienia", co z pewnością * nie * "wszystko" ... – Mehrdad

4

myślę część pytania pochodzi z założenia, że ​​podzielniki są użyteczne. Przydzielacze (przynajmniej pre-C++ 11) were something of a late addition to the STL:

Ludzie chcieli kontenerów niezależnych od modelu pamięci, co było nieco przesadzone, ponieważ język nie zawiera modeli pamięci. Ludzie chcieli, aby biblioteka zapewniała pewien mechanizm abstrakcji modeli pamięci. Wcześniejsze wersje STL zakładały, że rozmiar kontenera można wyrazić jako liczbę całkowitą typu size_t, a odległość między dwoma iteratorami jest typu ptrdiff_t. A teraz powiedziano nam, dlaczego nie można tego streścić? Jest to wysokie zamówienie, ponieważ język nie jest abstrakcyjny; Macierze C i C++ nie są sparametryzowane przez te typy. Wynaleźliśmy mechanizm o nazwie "alokator", który zawiera informację o modelu pamięci. To spowodowało poważne konsekwencje dla każdego komponentu w bibliotece. Można się zastanawiać, jakie modele pamięci mają do czynienia z algorytmami lub interfejsami kontenera. Jeśli nie możesz używać rzeczy takich jak size_t, nie możesz również używać rzeczy takich jak T* z powodu różnych typów wskaźników (T*, T huge * itd.). Wtedy nie możesz używać referencji, ponieważ w różnych modelach pamięci masz różne typy odniesienia. Istniały ogromne konsekwencje w bibliotece.

Niestety they turned out to be substandard:

wymyśliłem podzielników do czynienia z architekturą pamięci Intela. Nie są to takie złe idee w teorii - posiadające warstwę, która obejmuje całą pamięć: wskaźniki, odnośniki, ptrdiff_t, size_t. Niestety nie mogą one działać w praktyce. Na przykład,

vector<int, alloc1> a(...); 
vector<int, alloc2> b(...); 

nie można teraz powiedzieć:

find(a.begin(), a.end(), b[1]); 

b[1] zwraca alloc2::reference i nie int&. Może to być niedopasowanie typu. Konieczna jest zmiana sposobu, w jaki język podstawowy zajmuje się odwołaniami, aby alokatory naprawdę się przydały.

reference typedef ma powrócić cokolwiek odpowiednik T& jest dla podzielnika w pytaniu. Na nowoczesnych architekturach jest to prawdopodobnie T&. Założono jednak, że w niektórych architekturach może to być coś innego (np. Kompilator kierujący się architekturą z "bliskimi" i "daleko" wskaźnikami może potrzebować specjalnej składni dla odniesień "blisko" i "daleko"). Niestety, ten genialny pomysł okazał się mniej błyskotliwy. C++ 11 wprowadza istotne zmiany w alokatorach - dodając podzielniki podzielone na punkty - i model pamięci. Muszę przyznać, że nie wiem wystarczająco dużo o zmianach C++ 11 w.r.t. podzielników, aby powiedzieć, czy sytuacja się poprawi, czy pogorszy.


Patrząc na komentarze na oryginalne pytanie, ponieważ standard nie faktycznie stwierdzić, jak pojemniki muszą być realizowane (chociaż standard nie wkładać tak wiele wymagań na zachowanie pojemnikach, że równie dobrze. ..), niezależnie od typu, który wpisałeś jako reference, musisz mieć zachowanie T&, na którym ktoś mógłby potencjalnie polegać podczas implementacji kontenera: obiekt typu reference powinien być przezroczystym aliasem do oryginalnego obiektu, przypisanie do niego powinno zmienić wartość oryginalny obiekt bez przecinania, nie ma potrzeby obsługi "ponownego instalowania" reference, przyjmując adres reference powinien zwracać adres o obiekt sztywny itp. Jeśli to w ogóle możliwe, powinien być w rzeczywistości T&; i jedyny przypadek, w którym mogę sobie wyobrazić, gdzie nie byłoby to możliwe, byłby, gdybyś przydzielał pamięć, której nie mógłbyś manipulować przez wskaźniki lub referencje (np. gdyby "pamięć" była rzeczywiście na dysku, lub gdyby pamięć była rzeczywiście przydzielone na oddzielnym komputerze i dostępne przez sieć za pośrednictwem wywołań RPC itp.).

Wyrwane z normą
+0

To wydaje się być dla STL, a nie dla STD. – Pubby

+1

"Jedyny przypadek, w którym mogę sobie wyobrazić, gdzie nie byłoby to możliwe, gdybyś przydzielił pamięć, której nie mógłbyś manipulować wskaźnikami lub referencjami" Standard nie pozwoliłby ci na tworzenie alokatorów, ponieważ nie możesz udawać odniesienie w C++. Nie można podać semickiego odniesienia do obiektu. Dlatego 'wektor ' nie jest technicznie standardowym kontenerem. Nie stosuje się do reguł określonych dla instancji 'std :: vector'. I nie dzieje się tak, ponieważ musisz mieć możliwość wykonania '& vec [3]', co jest niemożliwe z 'wektorem '. –

+0

@Pubby: STL istniał przed standardem i został znacząco zmieniony, gdy stał się częścią standardu (jedna zmiana polegała na tym, że usunięto 2/3 algorytmów, które pierwotnie miał Stepanov). Według Stepanov, C++ zostało zmienione w pewien sposób, gdy STL został przyjęty do standardu (jedna zmiana to dodanie funktorów). Moje komentarze w ostatnim akapicie odpowiedzi są, jak sądzę, tylko "poprawne" dla C++ - 98. C++ - 03 zmienił reguły, tak że implementacje mogą zakładać, że "referencja" jest w rzeczywistości "T &" (jak wyraźnie stwierdza twoja odpowiedź). –

2

:

enter image description here

definiuje również reference jako typedef z value_type& co jest typedef z T

(New odpowiedzieć jak poprzedniego różnił focus)

Powiązane problemy