Twój kod wywołuje UB, ale nie dla przyczyn launder
. To dlatego, że p0[1].i
sam jest UB.
Tak naprawdę ([Expr.Add]/4)
Gdy wyrażenie ma integralną typu jest dodawane lub odejmowane od wskaźnika wynik musi typ argumentu wskaźnika. Jeśli wyrażenie P wskazuje na element x [i] obiektu tablicy x z n elementami, wyrażenia P + J i J + P (gdzie J ma wartość j) wskazują na (prawdopodobnie hipotetyczny) element x [i + j] jeśli 0 ≤ i + j ≤ n; w przeciwnym razie zachowanie jest niezdefiniowane. Podobnie wyrażenie P - J wskazuje na (prawdopodobnie hipotetyczny) element x [i - j], jeśli 0 ≤ i - j ≤ n; w przeciwnym razie zachowanie jest niezdefiniowane.
Obiekt, który nie jest elementem tablicy, jest uważany za należący do tablicy jednoelementowej do tego celu; patrz 8.3.1. Wskaźnik za ostatnim elementem tablicy x n elementów uważa się za równoważny wskaźnikowi do hipotetycznego elementu x [n] w tym celu; patrz 6.9.2.
[]
po zastosowaniu do wskaźnika oznacza wykonanie arytmetycznej wskazówki. W modelu obiektowym C++ arytmetykę wskaźnika można używać tylko na wskaźnikach do elementów w tablicy wskazanego typu. Zawsze możesz traktować obiekt jako tablicę o długości 1, dzięki czemu możesz uzyskać wskaźnik "jeden za końcem" pojedynczego obiektu. Tak więc, p0 + 1
jest ważny.
Co to jest nie valid uzyskuje dostęp do obiektu przechowywanego pod tym adresem, mimo że wskaźnik uzyskano za pomocą p0 + 1
. Oznacza to, że p0[1].i
jest niezdefiniowanym zachowaniem. To jest tak jak UB przed pranie jako po.
Teraz spójrzmy na inną możliwość:
X x[2];
x[1].~X(); //Destroy this object.
new(x + 1) X; //Construct a new one.
Warto więc zadać kilka pytań:
Czy x[1]
UB? Powiedziałbym ... nie, to nie jest UB. Czemu? Ponieważ x[1]
nie jest:
wskaźnik, który zwrócił się do oryginalnego obiektu, odniesienie, o którym mowa oryginalnego obiektu lub nazwa oryginalnego obiektu
x
punkty do tablicy i pierwszy element tej tablicy, a nie drugi element. Dlatego nie wskazuje na oryginalny obiekt. Nie jest to odniesienie, ani też nazwa tego obiektu.
Dlatego nie kwalifikuje się do ograniczeń określonych przez [basic.life]/8. Tak więc x[1]
powinien wskazywać na nowo skonstruowany obiekt.
Biorąc pod uwagę, że w ogóle nie potrzebujesz launder
.
Jeśli robisz to w sposób legalny, nie potrzebujesz tutaj launder
.
Czy nie jest "assert (p0 [1] == 43);" nieprawidłowe wyrażenie? ... Biorąc pod uwagę typ klasy tworzony przez podwyrażenie 'p0 [1]' nie ma przeciążonego 'operatora == (X, int)' – WhiZTiM
@ WhiZTiM Oczywiste literówka jest oczywista? – Barry
To był literówka. – Oliv