Eigenschaften eines Zeigers auf ein Array mit der Länge Null

21

Erwägen

int main()
{
    auto a = new int[0];
    delete[] a; // So there's no memory leak
}

Dürfen Sie zwischen der Initialisierung und dem Löschen der Kopie den Zeiger auf lesen a + 1?

Erlaubt die Sprache dem Compiler außerdem die Einstellung aauf nullptr?

Bathseba
quelle
2
@Fareanor: Sie können asicher lesen (Sie können es sicher nicht dereferenzieren).
Bathseba
8
@RasmiRanjanNayak: Das ist Quatsch.
Bathseba
2
@RasmiRanjanNayak Oh mein ... nein
Ted Lyngmo
1
@TedLyngmo: Wenn ich "Zeiger lesen bei a + 1" sage , ist der folgende Code auto b = a + 1;undefiniertes Verhalten? (Ich denke, es ist).
Bathseba
2
@ Ayxan Ich würde in dem Fall raten, wo 0tatsächlich das Ergebnis eines Ausdrucks ist, den Sie erst zur Laufzeit kennen. Da dies new int[0]sicher ist, können Sie sich keine Sorgen über Verzweigungs- / Sonderfälle machen. Stellen Sie sich vor, ich würde ein std::vectormit initialisieren std::vector<int> v(0);.
scohe001

Antworten:

3
    auto a = new int[0];

Gemäß [basic.compound.3] ist der ina einer der folgenden sein:

  1. Ein Zeiger auf ein Objekt (vom Typ) int )
  2. Ein Zeiger hinter dem Ende eines Objekts
  3. Null
  4. Ungültig

Wir können die erste Möglichkeit ausschließen, da keine Objekte vom Typ intkonstruiert wurden. Die dritte Möglichkeit ist ausgeschlossen, da in C ++ ein Nicht-Null-Zeiger zurückgegeben werden muss (siehe [basic.stc.dynamic.allocation.2] ). Wir haben also zwei Möglichkeiten: einen Zeiger hinter dem Ende eines Objekts oder einen ungültigen Zeiger.

Ich würde gerne als aZeiger über das Ende hinaus betrachten, aber ich habe keinen seriösen Hinweis, um dies endgültig festzustellen. (Es gibt jedoch eine starke Implikation in [basic.stc] , wenn Sie sehen, wie Sie deletediesen Zeiger verwenden können.) Daher werde ich in dieser Antwort beide Möglichkeiten erläutern .

Dürfen Sie zwischen der Initialisierung und dem Löschen der Kopie den Zeiger auf lesen a + 1?

Das Verhalten ist undefiniert, wie in [Ausdruck.add.4] vorgegeben , unabhängig davon, welche Möglichkeit von oben gilt.

Wenn aes sich um einen Past-the-End-Zeiger handelt, wird davon ausgegangen, dass er auf das hypothetische Element am Index 0eines Arrays ohne Elemente verweist. Das Hinzufügen der Ganzzahl jzu awird nur definiert, wenn 0≤0+j≤n, wo ndie Größe des Arrays ist. In unserem Fall nist Null, daher wird die Summe a+jnur definiert, wennj ist 0. Insbesondere ist das Hinzufügen 1undefiniert.

Wenn a es ungültig ist, fallen wir sauber in "Andernfalls ist das Verhalten undefiniert." (Es überrascht nicht, dass die definierten Fälle nur gültige Zeigerwerte abdecken.)

Ermöglicht die Sprache dem Compiler außerdem die Einstellung aaufnullptr?

Nein . Aus dem oben erwähnten [basic.stc.dynamic.allocation.2] : „Wenn die Anforderung erfolgreich ist , wird der Wert durch eine austauschbare Zuteilungsfunktion ist ein Nicht-Null - Zeiger - Wert zurückgegeben“ . Es gibt auch eine Fußnote, in der darauf hingewiesen wird, dass C ++ (aber nicht C) einen Nicht-Null-Zeiger als Antwort auf eine Null-Anforderung benötigt.

JaMiT
quelle
1
Wenn es sich um einen ungültigen Zeigerwert handelt, haben Sie ernsthafte Probleme mit eel.is/c++draft/basic.stc#4
TC
@TC True, das bedeutet stark, dass es kein ungültiger Zeigerwert sein kann.
JaMiT
23

Per jüngster Diskussion CWG Reflektor als Folge der redaktionellen Ausgabe 3178 , new int[0]produziert , was derzeit einen genannt „past-the-end“ Zeigerwert .

Daraus folgt, dass adies nicht null sein kann und a + 1durch [expr.add] / 4 nicht definiert ist .

TC
quelle
4
"Laut der jüngsten CWG-Reflektordiskussion als Ergebnis der redaktionellen Ausgabe 3178 new int[0]wird ein sogenannter" Past-the-End "-Zeigerwert erzeugt." Dies ist nicht korrekt. Es wurde nicht viel diskutiert. Eine Person schlug vor, dass der Wert "Zeiger nach dem Ende eines Objekts" sein sollte, und diese Aussage wurde in Frage gestellt, da bei einem Array mit 0Elementen kein Objekt nach dem Ende von vorhanden ist.
Sprachanwalt
@LanguageLawyer Es besteht kein Zweifel, dass dies a + 1auf jeden Fall undefiniert ist. Ihr Punkt bezieht sich also nur darauf, ob anull sein kann.
MM
Es schien keine Meinungsverschiedenheiten über die beabsichtigte Semantik zu geben, noch dass der aktuelle Name für diese Kategorie von Zeigerwerten für dieses Szenario schlecht geeignet ist.
TC
@MM Ich denke, das a + 1ist undefiniert und vielleicht wird der resultierende Zeigerwert "Zeiger nach dem Ende" genannt. Ich sage nicht, dass die Antwort falsch ist. Es ist etwas ungenau, da es so verstanden werden könnte, dass es eine lange Diskussion mit einem Konsens gab, dass die bloße Angabe, dass das Ergebnis "Zeiger nach dem Ende" ist, ausreicht, um das Problem zu lösen. Das Problem mit "Zeiger hinter dem Ende" besteht darin, dass es hinter dem Ende eines Objekts liegt und das Subtrahieren 1von einem solchen Zeigerwert einen Zeiger auf das Objekt ergibt, was bei Arrays von 0Elementen wahrscheinlich nicht der Fall sein sollte .
Sprachanwalt
2
@Bathsheba Glaubst du, dass fehlerhafte Formulierungen maßgeblicher sein könnten?
Sprachanwalt