Rozważać
int main()
{
auto a = new int[0];
delete[] a; // So there's no memory leak
}
Czy między inicjowaniem i usuwaniem kopii można odczytywać wskaźnik w a + 1
?
Ponadto, nie pozwalają na język kompilator zestaw a
do nullptr
?
c++
language-lawyer
Batszeba
źródło
źródło
a
na pewno czytać (z pewnością nie możesz tego wyrejestrować).a + 1
”, czy następujący kod jestauto b = a + 1;
niezdefiniowany? (Myślę, że to jest).0
rzeczywistości jest to wynik wyrażenia, którego nie poznasz do czasu uruchomienia. Ponieważnew int[0]
jest bezpieczny, może zaoszczędzić Ci martwienia się o niektóre rozgałęzienia / przypadki specjalne. Wyobraź sobie, że miałbym zainicjować zastd::vector
pomocąstd::vector<int> v(0);
.Odpowiedzi:
Zgodnie z [basic.compound.3] przechowywana wartość
a
musi być jedną z następujących czynności:int
)Możemy wykluczyć pierwszą możliwość, ponieważ nie zbudowano żadnych obiektów typu
int
. Trzecia możliwość jest wykluczona, ponieważ C ++ wymaga zwrotu niepustego wskaźnika (patrz [basic.stc.dynamic.allocation.2] ). Mamy zatem dwie możliwości: wskaźnik za końcem obiektu lub nieprawidłowy wskaźnik.Byłbym skłonny postrzegać
a
jako wskaźnik przeszłości, ale nie mam renomowanego odniesienia, aby definitywnie to ustalić. (Istnieje jednak silna implikacja tego w [basic.stc] , widząc, jak możnadelete
ten wskaźnik.) W związku z tym przedstawię obie możliwości.Zachowanie jest niezdefiniowane, jak podyktowane jest to [expr.add.4] , niezależnie od tego, która z powyższych możliwości ma zastosowanie.
Jeśli
a
wskaźnik jest końcowy, uważa się, że wskazuje hipotetyczny element na indeks0
tablicy bez elementów. Dodanie liczby całkowitejj
doa
jest definiowane tylko wtedy0≤0+j≤n
, gdy , gdzien
jest rozmiar tablicy. W naszym przypadkun
wynosi zero, więc sumaa+j
jest definiowana tylko wtedy, gdyj
jest0
. W szczególności dodawanie1
jest niezdefiniowane.Jeśli
a
jest nieważny, wówczas czysto popadamy w „W przeciwnym razie zachowanie jest niezdefiniowane”. (Nic dziwnego, że zdefiniowane przypadki obejmują tylko prawidłowe wartości wskaźnika).Nie. Z wyżej wspomnianego [basic.stc.dynamic.allocation.2] : „Jeśli żądanie powiedzie się, wartość zwrócona przez wymienną funkcję alokacji jest wartością wskaźnika o wartości innej niż zero” . Istnieje również przypis wzywający, że C ++ (ale nie C) wymaga niepustego wskaźnika w odpowiedzi na żądanie zerowe.
źródło
Na podstawie ostatniej dyskusji odbłyśnika CWG w wyniku wydania redakcyjnego 3178
new int[0]
produkuje to , co obecnie nazywa się „past-the-end” wartość wskaźnika .Wynika z tego, że
a
nie może być zerowy ia + 1
jest niezdefiniowany przez [expr.add] / 4 .źródło
new int[0]
powstaje tak zwana wartość wskaźnika„ z przeszłości ”. Nie jest to dokładne. Nie było dużo dyskusji. Jedna osoba zasugerowała, że wartość powinna być „wskaźnikiem za końcem obiektu”, a to stwierdzenie zostało zakwestionowane, ponieważ w przypadku tablicy z0
elementami nie ma obiektu, który mógłby zostać przekroczony.a + 1
w żadnym wypadku nie jest on zdefiniowany, więc twój punkt dotyczy tylko tego, czya
może być zerowy?a + 1
jest to niezdefiniowane i być może wynikowa wartość wskaźnika zostanie nazwana „wskaźnikiem za końcem”. Nie twierdzę, że odpowiedź jest zła. Jest to nieco nieprecyzyjne, ponieważ można to rozumieć jako długą dyskusję z konsensusem, że wystarczy jedynie sprecyzowanie, że wynikiem jest „wskaźnik za końcem”, aby rozwiązać problem. Problem z „wskaźnikiem za końcem” polega na tym, że jest on powyżej końca jakiegoś obiektu, a odjęcie1
od takiej wartości wskaźnika daje jeden wskaźnik do obiektu, co prawdopodobnie nie powinno mieć miejsca w przypadku tablic0
elementów.