2017-06-06 65 views
5

Uwaga: to pytanie nie dotyczy zamówienia całkowitego. Całkowite zamówienie na wskaźniki tego samego typu można uzyskać za pomocą std::less.Czy operator <(mniej niż) na wskaźnikach jest zgodny?

According to this, porównanie dwóch wskaźników z operator< jest niedozwolone, jeśli wskazują one na przykład na różne alokacje.

W jakim sensie nie jest to dozwolone? Czy jest to zdefiniowane przez implementację, nieokreślone lub niezdefiniowane zachowanie?

Chyba czytałem gdzieś, że jest nieokreślone. Implementacja nie jest wymagana do udokumentowania tego, co to jest zachowanie, ale musi być pewne zachowanie. Oznaczałoby to, że porównywanie dowolnych dwóch wskaźników jest nadal zgodne z prawem, ale niekoniecznie daje całkowitą kolejność. Czy to oznacza, że ​​wciąż musimy uzyskać spójny wynik, porównując dwa razy te same wskaźniki? Ogólny przypadek: czy wywołanie tego samego nieokreślonego zachowania dwa razy w aplikacji zawsze daje taki sam wynik?

int i1, i2; 
int* a = &i1; 
int* b = &i2; 
bool b1 = a < b; // unspecified, right? 
bool b2 = a < b; 
assert(b1 == b2); // Is this guaranteed to be true? 

Odpowiedz

4

Porównując dwóch niepowiązanych wskazówek (to znaczy nie wskaźniki wskazujące tej samej pamięci, czy nie, wskazujący na różnych częściach tej samej „macierzy”) może być dokonywane jedynie za pomocą równości == i nierówności !=. Wszystkie pozostałe porównania to nieokreślone.

Jeśli masz dwa wskaźniki wskazujące na to samo miejsce lub wewnątrz tej samej tablicy, możesz porównać je za pomocą odpowiednich operatorów

Więc jeśli masz np.

int* p1 = new int[10]; 
int* p2 = new int[5]; 

można tylko użycie == i != porównać wskaźniki p1 i p2.

Ale jeśli masz

int a = new int[10]; 
int* p1 = &a[0]; 
int* p2 = &a[3]; 

następnie można użyć również < i > (i oczywiście <= i >=) porównać p1 i p2

+0

Czy masz konkretnego odniesienia, który mówi, że jest to undefined * *? Czytając * [expr.rel] *, rozumiem, że jest * nieokreślony *. – Holt

+0

[tutaj] (http://eel.is/c++draft/expr.rel # 3), mówi w trzecim punkcie, że _W przeciwnym razie żaden ze wskaźników nie porównuje więcej niż drugi_. To nie jest dokładnie UB. Czy się mylę? – skypjack

+2

Z połączonej odpowiedzi SO: "Można jednak użyć std :: less, a inne obiekty funkcji porównywania relacyjnego porównywać dowolne dwa wskaźniki. Wyniki są definiowane przez implementację, ale gwarantuje się całkowitą kolejność." –

-1

Porównując wskaźniki, jak pokazano w przykładzie ma sensu ponieważ wartość "a" i "b" zależy od tego, w jaki sposób dane są przechowywane w pamięci, a nie od zawartości zapisanej w tej lokalizacji.

Wskaźniki to adresy w pamięci (zwykle przechowywane jako 32-bitowa liczba całkowita). Jeśli nie zmienisz żadnego z nich, ich porównanie zwróci ten sam wynik. Możesz nie wiedzieć, co to za wynik, ale będziesz wiedział, że za każdym razem będzie tak samo.

Dlatego w twoim przypadku otrzymasz taki sam wynik zarówno dla b1 jak i b2, więc asercja przejdzie.

Oto przykład, gdzie wskaźniki porównujące ma sensu:

int data[1000]; 
int *end = data + 50; 
for (int *c = data; c < end; c++) 
    ... use *c 
+0

* Wartości "a" i "b" zależą od tego, jak przechowywane są dane w pamięci * W praktyce jest to zwykle prawda, ale zachowanie jest faktycznie * niezdefiniowane *. W przypadku przykładu pytania kompilator może po prostu zoptymalizować cały ten kod. W takim przypadku pamięć nie wchodzi w ogóle w grę. –

+0

Dla mnie jest to niezdefiniowane w tym sensie, że nie można przewidzieć wyniku. Chodzi mi o to, że chociaż wynik nie jest przewidywalny, jest spójny. – user3429660

+2

Termin * niezdefiniowane zachowanie * w C++ ma [ścisłe znaczenie] (http://en.cppreference.com/w/cpp/language/ub). Oznacza to, że nie można racjonalnie przewidzieć zachowania niczego, co przejawia * niezdefiniowane zachowanie *. Kompilator może wykryć, że wszystkie zmienne w przykładzie są niezainicjowane. Może wtedy przyjąć, że wynikiem '* undefined * == * undefined *' jest to, co jest najwygodniejsze dla jego optymalizacji. Nie można założyć, że 'b1 == b2' jest' prawda'. Edytuj: pytanie zostało zmodyfikowane, ponieważ ten komentarz został napisany. –