Das ist legal:
int array[5];
int *array_begin = &array[0];
int *array_end = &array[5];
Abschnitt 5.2.1 Abonnement Der Ausdruck E1 [E2] ist (per Definition) identisch mit * ((E1) + (E2))
Damit können wir also sagen, dass array_end auch äquivalent ist:
int *array_end = &(*((array) + 5));
Abschnitt 5.3.1.1 Unärer Operator '*': Der unäre * Operator führt eine Indirektion durch: Der Ausdruck, auf den er angewendet wird, muss ein Zeiger auf einen Objekttyp oder ein Zeiger auf einen Funktionstyp sein, und das Ergebnis ist ein Wert, der sich auf das Objekt bezieht oder Funktion, auf die der Ausdruck zeigt. Wenn der Typ des Ausdrucks "Zeiger auf T" ist, ist der Typ des Ergebnisses "T". [Hinweis: Ein Zeiger auf einen unvollständigen Typ (außer cv void) kann dereferenziert werden. Der so erhaltene Wert kann auf begrenzte Weise verwendet werden (zum Beispiel zum Initialisieren einer Referenz); Dieser Wert darf nicht in einen Wert umgewandelt werden, siehe 4.1. - Endnote]
Der wichtige Teil des oben genannten:
'Das Ergebnis ist ein Wert, der sich auf das Objekt oder die Funktion bezieht.'
Der unäre Operator '*' gibt einen l-Wert zurück, der sich auf den int bezieht (keine Referenzierung). Der unäre Operator '&' erhält dann die Adresse des Wertes.
Solange es keine De-Referenzierung eines Zeigers außerhalb der Grenzen gibt, wird die Operation vollständig vom Standard abgedeckt und das gesamte Verhalten wird definiert. Nach meiner Lektüre ist das oben Gesagte völlig legal.
Die Tatsache, dass viele der STL-Algorithmen vom genau definierten Verhalten abhängen, ist eine Art Hinweis, den das Normungsgremium bereits hat, und ich bin sicher, dass es etwas gibt, das dies explizit abdeckt.
Der Kommentarbereich unten enthält zwei Argumente:
(Bitte lesen Sie: aber es ist lang und wir beide enden trollisch)
Argument 1
Dies ist aufgrund von Abschnitt 5.7 Absatz 5 illegal
Wenn ein Ausdruck mit einem integralen Typ zu einem Zeiger hinzugefügt oder von diesem subtrahiert wird, hat das Ergebnis den Typ des Zeigeroperanden. Wenn der Zeigeroperand auf ein Element eines Array-Objekts zeigt und das Array groß genug ist, zeigt das Ergebnis auf ein Element, das vom ursprünglichen Element versetzt ist, sodass die Differenz der Indizes der resultierenden und ursprünglichen Array-Elemente dem integralen Ausdruck entspricht. Mit anderen Worten, wenn der Ausdruck P auf das i-te Element eines Array-Objekts zeigt, zeigen die Ausdrücke (P) + N (äquivalent N + (P)) und (P) -N (wobei N den Wert n hat) zu den i + n-ten bzw. i - n-ten Elementen des Array-Objekts, sofern sie existieren. Wenn der Ausdruck P auf das letzte Element eines Array-Objekts zeigt, zeigt der Ausdruck (P) +1 außerdem eins nach dem letzten Element des Array-Objekts. und wenn der Ausdruck Q eins nach dem letzten Element eines Array-Objekts zeigt, zeigt der Ausdruck (Q) -1 auf das letzte Element des Array-Objekts. Wenn sowohl der Zeigeroperand als auch das Ergebnis auf Elemente desselben Arrayobjekts oder eines nach dem letzten Element des Arrayobjekts zeigen, darf die Auswertung keinen Überlauf erzeugen. Andernfalls ist das Verhalten undefiniert.
Und obwohl der Abschnitt relevant ist; Es zeigt kein undefiniertes Verhalten. Alle Elemente in dem Array, über die wir sprechen, befinden sich entweder innerhalb des Arrays oder eines nach dem Ende (was im obigen Absatz gut definiert ist).
Argument 2:
Das zweite Argument, das unten dargestellt wird, ist: *
ist der De-Referenz-Operator.
Und obwohl dies ein gebräuchlicher Begriff ist, der verwendet wird, um den Operator '*' zu beschreiben; Dieser Begriff wird im Standard bewusst vermieden, da der Begriff "De-Reference" in Bezug auf die Sprache und die Bedeutung für die zugrunde liegende Hardware nicht genau definiert ist.
Obwohl der Zugriff auf den Speicher über das Ende des Arrays hinaus definitiv undefiniertes Verhalten ist. Ich bin nicht davon überzeugt, dass der unary * operator
Zugriff auf den Speicher (Lesen / Schreiben in den Speicher) in diesem Zusammenhang (nicht in einer vom Standard definierten Weise) erfolgt. In diesem Zusammenhang (wie im Standard definiert (siehe 5.3.1.1)) gibt die unary * operator
Rückgabe a lvalue referring to the object
. Nach meinem Verständnis der Sprache ist dies kein Zugriff auf den zugrunde liegenden Speicher. Das Ergebnis dieses Ausdrucks wird dann sofort vom unary & operator
Operator verwendet, der die Adresse des Objekts zurückgibt, auf das der lvalue referring to the object
.
Viele andere Verweise auf Wikipedia und nicht kanonische Quellen werden vorgestellt. All das finde ich irrelevant. C ++ wird durch den Standard definiert .
Fazit:
Ich möchte zugeben, dass es viele Teile des Standards gibt, die ich möglicherweise nicht berücksichtigt habe und die möglicherweise beweisen, dass meine obigen Argumente falsch sind. NON sind unten angegeben. Wenn Sie mir eine Standardreferenz zeigen, die dies zeigt, ist dies UB. ich werde
- Hinterlasse die Antwort.
- Setzen Sie alle Kappen ein, das ist dumm und ich bin falsch, dass alle lesen.
Dies ist kein Argument:
Nicht alles auf der ganzen Welt ist durch den C ++ - Standard definiert. Öffne deinen Geist.