Pointer declaration
Deklariert eine Variable eines Zeiger- oder Zeiger-auf-Member-Typs.
Inhaltsverzeichnis |
Syntax
Eine Zeigerdeklaration ist jede einfache Deklaration, deren Deklarator die Form hat
*
attr
(optional)
cv
(optional)
declarator
|
(1) | ||||||||
nested-name-specifier
*
attr
(optional)
cv
(optional)
declarator
|
(2) | ||||||||
S
bestimmt wird.
C
vom Typ, bestimmt durch die Deklarationsspezifizierer-Sequenz
S
.
| nested-name-specifier | - |
eine
Folge von Namen und Bereichsauflösungsoperatoren
::
|
| attr | - | (since C++11) eine Liste von Attributen |
| cv | - | const/volatile-Qualifizierung, die auf den Zeiger angewendet wird, der deklariert wird (nicht auf den gezeigten Typ, dessen Qualifizierungen Teil der Deklarationsspezifizierer-Sequenz sind) |
| declarator | - | ein beliebiger Deklarator |
Es gibt keine Zeiger auf references und es gibt keine Zeiger auf bit-fields . Typischerweise schließen Erwähnungen von "Zeigern" ohne nähere Spezifikation keine Zeiger auf (nicht-statische) Member ein.
Zeiger
Jeder Wert vom Zeigertyp ist einer der Folgenden:
- ein Zeiger auf ein Objekt oder eine Funktion (in diesem Fall sagt man, der Zeiger zeigt auf das Objekt oder die Funktion), oder
- ein Zeiger hinter das Ende eines Objekts , oder
- der Nullzeigerwert für diesen Typ, oder
- ein ungültiger Zeigerwert .
Ein Zeiger, der auf ein Objekt zeigt, repräsentiert die Adresse des ersten Bytes im Speicher, das vom Objekt belegt wird. Ein Zeiger hinter dem Ende eines Objekts repräsentiert die Adresse des ersten Bytes im Speicher nach dem Ende des vom Objekt belegten Speicherbereichs.
Beachten Sie, dass zwei Zeiger, die dieselbe Adresse repräsentieren, dennoch unterschiedliche Werte haben können.
struct C { int x, y; } c; int* px = &c.x; // Wert von px ist "Zeiger auf c.x" int* pxe= px + 1; // Wert von pxe ist "Zeiger hinter das Ende von c.x" int* py = &c.y; // Wert von py ist "Zeiger auf c.y" assert(pxe == py); // == prüft, ob zwei Zeiger dieselbe Adresse repräsentieren // kann ausgelöst werden oder nicht *pxe = 1; // undefiniertes Verhalten, selbst wenn die Assertion nicht ausgelöst wird
Die Indirektion über einen ungültigen Zeigerwert und das Übergeben eines ungültigen Zeigerwerts an eine Freigabefunktion haben undefiniertes Verhalten. Jede andere Verwendung eines ungültigen Zeigerwerts hat implementierungsdefiniertes Verhalten. Einige Implementierungen könnten definieren, dass das Kopieren eines ungültigen Zeigerwerts einen systemgenerierten Laufzeitfehler verursacht.
Zeiger auf Objekte
Ein Zeiger auf ein Objekt kann mit dem Rückgabewert des Adressoperators initialisiert werden, angewendet auf jeden Ausdruck vom Objekttyp, einschließlich eines anderen Zeigertyps:
int n; int* np = &n; // Zeiger auf int int* const* npp = &np; // nicht-konstanter Zeiger auf konstanten Zeiger auf nicht-konstanten int int a[2]; int (*ap)[2] = &a; // Zeiger auf Array von int struct S { int n; }; S s = {1}; int* sp = &s.n; // Zeiger auf den int, der ein Member von s ist
Zeiger können als Operanden für den eingebauten Dereferenzierungsoperator (unären operator * ) erscheinen, der den Lvalue-Ausdruck zurückgibt, der das referenzierte Objekt identifiziert:
int n; int* p = &n; // Zeiger auf n int& r = *p; // Referenz ist an den Lvalue-Ausdruck gebunden, der n identifiziert r = 7; // speichert den int-Wert 7 in n std::cout << *p; // Lvalue-zu-Rvalue implizite Konvertierung liest den Wert aus n
Zeiger auf Klassenobjekte können auch als linke Operanden der Elementzugriffsoperatoren
operator->
und
operator->*
auftreten.
Aufgrund der Array-zu-Zeiger impliziten Konvertierung kann ein Zeiger auf das erste Element eines Arrays mit einem Ausdruck vom Array-Typ initialisiert werden:
int a[2]; int* p1 = a; // Zeiger auf das erste Element a[0] (ein int) des Arrays a int b[6][3][8]; int (*p2)[3][8] = b; // Zeiger auf das erste Element b[0] des Arrays b, // welches ein Array von 3 Arrays mit 8 ints ist
Aufgrund der abgeleitet-zu-basis impliziten Konvertierung für Zeiger kann ein Zeiger auf eine Basisklasse mit der Adresse einer abgeleiteten Klasse initialisiert werden:
struct Base {}; struct Derived : Base {}; Derived d; Base* p = &d;
` Tags wurde nicht übersetzt - C++ spezifische Begriffe wie `struct`, `Base`, `Derived` etc. wurden nicht übersetzt - Die Formatierung und Struktur des Originalcodes bleibt vollständig erhalten Der Code demonstriert eine einfache Vererbung in C++, bei der eine `Derived`-Klasse von einer `Base`-Klasse erbt und ein Zeiger auf die Basisklasse auf ein Objekt der abgeleiteten Klasse zeigt.
Wenn
Derived
polymorphe
ist, kann ein solcher Zeiger verwendet werden, um
virtuelle Funktionsaufrufe
durchzuführen.
Bestimmte Additions-, Subtraktions- , Inkrement- und Dekrement- Operatoren sind für Zeiger auf Array-Elemente definiert: Solche Zeiger erfüllen die LegacyRandomAccessIterator Anforderungen und ermöglichen es den C++- Algorithmusbibliotheken , mit Roh-Arrays zu arbeiten.
Vergleichsoperatoren sind in einigen Situationen für Zeiger auf Objekte definiert: zwei Zeiger, die dieselbe Adresse repräsentieren, vergleichen gleich, zwei Nullzeigerwerte vergleichen gleich, Zeiger auf Elemente desselben Arrays vergleichen gleich den Array-Indizes dieser Elemente, und Zeiger auf nicht-statische Datenelemente mit demselben Member-Zugriff vergleichen in der Reihenfolge der Deklaration dieser Member.
Viele Implementierungen bieten auch eine strikte Totalordnung von Zeigern beliebiger Herkunft, z.B. wenn sie als Adressen innerhalb eines kontinuierlichen virtuellen Adressraums implementiert sind. Jene Implementierungen, die dies nicht tun (z.B. wenn nicht alle Bits des Zeigers Teil einer Speicheradresse sind und für Vergleiche ignoriert werden müssen, oder eine zusätzliche Berechnung erforderlich ist oder Zeiger und Ganzzahl keine 1-zu-1-Beziehung haben), bieten eine Spezialisierung von std::less für Zeiger an, die diese Garantie bietet. Dies ermöglicht die Verwendung aller Zeiger beliebiger Herkunft als Schlüssel in standardmäßigen assoziativen Containern wie std::set oder std::map .
Zeiger auf void
Zeiger auf Objekte beliebigen Typs können
implizit konvertiert
werden in Zeiger auf (möglicherweise
cv-qualifiziertes
)
void
; der Zeigerwert bleibt unverändert. Die umgekehrte Konvertierung, die
static_cast
oder
explizite Konvertierung
erfordert, liefert den ursprünglichen Zeigerwert:
int n = 1; int* p1 = &n; void* pv = p1; int* p2 = static_cast<int*>(pv); std::cout << *p2 << '\n'; // gibt 1 aus
Wenn der ursprüngliche Zeiger auf ein Basisklassen-Subobjekt innerhalb eines Objekts eines polymorphen Typs zeigt,
dynamic_cast
kann verwendet werden, um einen
void
*
zu erhalten, der auf das vollständige Objekt des am meisten abgeleiteten Typs zeigt.
Zeiger auf void haben die gleiche Größe, Darstellung und Ausrichtung wie Zeiger auf char .
Zeiger auf
void
werden verwendet, um Objekte unbekannten Typs zu übergeben, was in C-Schnittstellen üblich ist:
std::malloc
gibt
void
*
zurück,
std::qsort
erwartet einen benutzerdefinierten Callback, der zwei
const
void
*
-Argumente akzeptiert.
pthread_create
erwartet einen benutzerdefinierten Callback, der
void
*
akzeptiert und zurückgibt. In allen Fällen ist es die Verantwortung des Aufrufers, den Zeiger vor der Verwendung in den korrekten Typ umzuwandeln.
Zeiger auf Funktionen
Ein Zeiger auf Funktion kann mit der Adresse einer Nicht-Mitgliedsfunktion oder einer statischen Mitgliedsfunktion initialisiert werden. Wegen der Funktion-zu-Zeiger impliziten Konvertierung ist der Address-of-Operator optional:
void f(int); void (*p1)(int) = &f; void (*p2)(int) = f; // identisch mit &f
Im Gegensatz zu Funktionen oder Referenzen auf Funktionen sind Zeiger auf Funktionen Objekte und können daher in Arrays gespeichert, kopiert, zugewiesen usw. werden.
void (a[10])(int); // Fehler: Array von Funktionen void (&a[10])(int); // Fehler: Array von Referenzen void (*a[10])(int); // OK: Array von Funktionszeigern
Hinweis: Deklarationen mit Zeigern auf Funktionen können oft durch Typaliase vereinfacht werden:
using F = void(int); // benannter Typalias zur Vereinfachung von Deklarationen F a[10]; // Fehler: Array von Funktionen F& a[10]; // Fehler: Array von Referenzen F* a[10]; // OK: Array von Zeigern auf Funktionen
Ein Zeiger auf Funktion kann als linker Operand des Funktionsaufrufoperators verwendet werden, dies ruft die gezeigte Funktion auf:
int f(int n) { std::cout << n << '\n'; return n * n; } int main() { int (*p)(int) = f; int x = p(7); }
Das Dereferenzieren eines Funktionszeigers ergibt den L-Wert, der die gezeigte Funktion identifiziert:
int f(); int (*p)() = f; // Zeiger p zeigt auf f int (&r)() = *p; // der L-Wert, der f identifiziert, ist an eine Referenz gebunden r(); // Funktion f wird über L-Wert-Referenz aufgerufen (*p)(); // Funktion f wird über den Funktions-L-Wert aufgerufen p(); // Funktion f wird direkt über den Zeiger aufgerufen
Ein Zeiger auf eine Funktion kann von einem Überladungssatz initialisiert werden, der Funktionen, Funktions-Template-Spezialisierungen und Funktions-Templates enthalten kann, falls nur eine Überladung zum Typ des Zeigers passt (siehe Adresse einer überladenen Funktion für weitere Details):
template<typename T> T f(T n) { return n; } double f(double n) { return n; } int main() { int (*p)(int) = f; // instanziiert und wählt f<int> aus }
Gleichheitsvergleichsoperatoren sind für Zeiger auf Funktionen definiert (sie vergleichen gleich, wenn sie auf dieselbe Funktion zeigen).
Zeiger auf Member
Zeiger auf Datenelemente
Ein Zeiger auf ein nicht-statisches Mitgliedsobjekt
m
, das Mitglied der Klasse
C
ist, kann exakt mit dem Ausdruck
&
C
::
m
initialisiert werden. Ausdrücke wie
&
(
C
::
m
)
oder
&
m
innerhalb der Mitgliedsfunktion von
C
bilden keine Zeiger auf Mitglieder.
Ein solcher Zeiger kann als rechter Operand der Zeiger-auf-Member-Zugriffsoperatoren operator. * und operator - > * verwendet werden:
Zeiger auf ein Datenmitglied einer zugänglichen eindeutigen nicht-virtuellen Basisklasse kann implizit konvertiert werden zu einem Zeiger auf dasselbe Datenmitglied einer abgeleiteten Klasse:
struct Base { int m; }; struct Derived : Base {}; int main() { int Base::* bp = &Base::m; int Derived::* dp = bp; Derived d; d.m = 1; std::cout << d.*dp << ' ' << d.*bp << '\n'; // gibt 1 1 aus }
Die Umwandlung in die entgegengesetzte Richtung, von einem Zeiger auf ein Datenelement einer abgeleiteten Klasse zu einem Zeiger auf ein Datenelement einer eindeutigen nicht-virtuellen Basisklasse, ist erlaubt mit
static_cast
und
explicit cast
, selbst wenn die Basisklasse dieses Element nicht besitzt (aber die am stärksten abgeleitete Klasse es besitzt, wenn der Zeiger für den Zugriff verwendet wird):
Der gezeigte Typ eines Zeigers-auf-Mitglied kann selbst ein Zeiger-auf-Mitglied sein: Zeiger auf Mitglieder können mehrstufig sein und können auf jeder Ebene unterschiedlich cv-qualifiziert sein. Gemischte mehrstufige Kombinationen von Zeigern und Zeigern-auf-Mitglieder sind ebenfalls erlaubt:
struct A { int m; // konstanter Zeiger auf nicht-konstantes Member int A::* const p; }; int main() { // nicht-konstanter Zeiger auf Datenmember, der ein konstanter Zeiger auf nicht-konstantes Member ist int A::* const A::* p1 = &A::p; const A a = {1, &A::m}; std::cout << a.*(a.*p1) << '\n'; // gibt 1 aus // regulärer nicht-konstanter Zeiger auf einen konstanten Zeiger-auf-Member int A::* const* p2 = &a.p; std::cout << a.**p2 << '\n'; // gibt 1 aus }
` und `` Tags wurde nicht übersetzt
- C++ spezifische Begriffe wie "struct", "int", "const", "cout" etc. wurden beibehalten
- Kommentare wurden präzise ins Deutsche übersetzt
- "prints" wurde als "gibt aus" übersetzt (übliche deutsche Programmierterminologie)
- Zeiger-Konzepte wurden fachgerecht übersetzt ("pointer" → "Zeiger", "member" → "Member")
Zeiger auf Memberfunktionen
Ein Zeiger auf eine nicht-statische Member-Funktion
f
die eine Member-Klasse
C
ist, kann exakt mit dem Ausdruck
&
C
::
f
initialisiert werden. Ausdrücke wie
&
(
C
::
f
)
oder
&
f
innerhalb von
C
's Member-Funktion bilden keine Zeiger auf Member-Funktionen.
Ein solcher Zeiger kann als rechter Operand der Zeiger-auf-Member-Zugriffsoperatoren operator. * und operator - > * verwendet werden. Der resultierende Ausdruck kann nur als linker Operand eines Funktionsaufrufoperators verwendet werden:
struct C { void f(int n) { std::cout << n << '\n'; } }; int main() { void (C::* p)(int) = &C::f; // Zeiger auf Memberfunktion f der Klasse C C c; (c.*p)(1); // gibt 1 aus C* cp = &c; (cp->*p)(2); // gibt 2 aus }
Zeiger auf Memberfunktion einer Basisklasse können
implizit konvertiert werden
zu Zeigern auf dieselbe Memberfunktion einer abgeleiteten Klasse:
struct Base { void f(int n) { std::cout << n << '\n'; } }; struct Derived : Base {}; int main() { void (Base::* bp)(int) = &Base::f; void (Derived::* dp)(int) = bp; Derived d; (d.*dp)(1); (d.*bp)(2); }
Die Umwandlung in die entgegengesetzte Richtung, von einem Zeiger auf eine Memberfunktion einer abgeleiteten Klasse zu einem Zeiger auf eine Memberfunktion einer eindeutigen nicht-virtuellen Basisklasse, ist erlaubt mit
static_cast
und
explicit cast
, selbst wenn die Basisklasse diese Memberfunktion nicht besitzt (aber die am stärksten abgeleitete Klasse besitzt sie, wenn der Zeiger für den Zugriff verwendet wird):
struct Base {}; struct Derived : Base { void f(int n) { std::cout << n << '\n'; } }; int main() { void (Derived::* dp)(int) = &Derived::f; void (Base::* bp)(int) = static_cast<void (Base::*)(int)>(dp); Derived d; (d.*bp)(1); // in Ordnung: gibt 1 aus Base b; (b.*bp)(2); // undefiniertes Verhalten }
Zeiger auf Memberfunktionen können als Callbacks oder als Funktionsobjekte verwendet werden, oft nach Anwendung von std::mem_fn oder std::bind :
#include <algorithm> #include <cstddef> #include <functional> #include <iostream> #include <string> int main() { std::vector<std::string> v = {"a", "ab", "abc"}; std::vector<std::size_t> l; transform(v.begin(), v.end(), std::back_inserter(l), std::mem_fn(&std::string::size)); for (std::size_t n : l) std::cout << n << ' '; std::cout << '\n'; }
Ausgabe:
1 2 3
Null-Zeiger
Zeiger jedes Typs haben einen speziellen Wert, der als null pointer value dieses Typs bekannt ist. Ein Zeiger, dessen Wert null ist, zeigt nicht auf ein Objekt oder eine Funktion (das Verhalten beim Dereferenzieren eines null-Zeigers ist undefiniert) und vergleicht gleich mit allen Zeigern desselben Typs, deren Wert ebenfalls null ist.
Ein null pointer constant kann verwendet werden, um einen Zeiger auf null zu initialisieren oder den null-Wert einem bestehenden Zeiger zuzuweisen. Es handelt sich um einen der folgenden Werte:
- Ein Integer-Literal mit dem Wert null.
|
(seit C++11) |
Das Makro NULL kann ebenfalls verwendet werden, es expandiert zu einer implementierungsdefinierten Nullzeigerkonstante.
Zero-Initialisierung und Wert-Initialisierung initialisieren ebenfalls Zeiger auf ihre Nullwerte.
Nullzeiger können verwendet werden, um das Fehlen eines Objekts anzuzeigen (z.B. std::function::target() ), oder als andere Fehlerzustandsindikatoren (z.B. dynamic_cast ). Allgemein muss eine Funktion, die einen Zeigerparameter empfängt, fast immer prüfen, ob der Wert null ist und diesen Fall anders behandeln (beispielsweise tut der delete-Ausdruck nichts, wenn ein Nullzeiger übergeben wird).
Ungültige Zeiger
Ein Zeigerwert p ist gültig im Kontext von einer Auswertung e wenn eine der folgenden Bedingungen erfüllt ist:
- p ist ein Nullzeigerwert.
- p ist ein Zeiger auf eine Funktion.
- p ist ein Zeiger auf oder hinter das Ende eines Objekts o , und e befindet sich in der Speicherdauer des Speicherbereichs für o .
Wenn ein Zeigerwert p in einer Auswertung e verwendet wird und p im Kontext von e nicht gültig ist, dann:
- Wenn e eine Indirektion oder ein Aufruf einer Freigabefunktion ist, ist das Verhalten undefiniert.
- Andernfalls ist das Verhalten implementierungsdefiniert.
int* f() { int obj; int* local_ptr = new (&obj) int; *local_ptr = 1; // OK, die Auswertung „*local_ptr“ befindet sich // in der Speicherdauer von „obj“ return local_ptr; } int* ptr = f(); // die Speicherdauer von „obj“ ist abgelaufen, // daher ist „ptr“ in den folgenden Kontexten ein ungültiger Zeiger int* copy = ptr; // implementierungsdefiniertes Verhalten *ptr = 2; // undefiniertes Verhalten: Dereferenzierung eines ungültigen Zeigers delete ptr; // undefiniertes Verhalten: Freigabe von Speicher über einen ungültigen Zeiger
Konstanz
-
Wenn
cv
vor
*in der Pointer-Deklaration erscheint, ist es Teil der Deklarationsspezifizierer-Sequenz und bezieht sich auf das Objekt, auf das gezeigt wird. -
Wenn
cv
nach
*in der Pointer-Deklaration erscheint, ist es Teil des Deklarators und bezieht sich auf den Pointer, der deklariert wird.
| Syntax | Bedeutung |
|---|---|
| const T * | Zeiger auf konstantes Objekt |
| T const * | Zeiger auf konstantes Objekt |
| T * const | Konstanter Zeiger auf Objekt |
| const T * const | Konstanter Zeiger auf konstantes Objekt |
| T const * const | Konstanter Zeiger auf konstantes Objekt |
// pc ist ein nicht-konstanter Zeiger auf konstantes int // cpc ist ein konstanter Zeiger auf konstantes int // ppc ist ein nicht-konstanter Zeiger auf nicht-konstanten Zeiger auf konstantes int const int ci = 10, *pc = &ci, *const cpc = pc, **ppc; // p ist ein nicht-konstanter Zeiger auf nicht-konstantes int // cp ist ein konstanter Zeiger auf nicht-konstantes int int i, *p, *const cp = &i; i = ci; // okay: Wert des konstanten int wird in nicht-konstantes int kopiert *cp = ci; // okay: nicht-konstantes int (gezeigt durch konstanten Zeiger) kann geändert werden pc++; // okay: nicht-konstanter Zeiger (auf konstantes int) kann geändert werden pc = cpc; // okay: nicht-konstanter Zeiger (auf konstantes int) kann geändert werden pc = p; // okay: nicht-konstanter Zeiger (auf konstantes int) kann geändert werden ppc = &pc; // okay: Adresse eines Zeigers auf konstantes int ist Zeiger auf Zeiger auf konstantes int ci = 1; // Fehler: konstantes int kann nicht geändert werden ci++; // Fehler: konstantes int kann nicht geändert werden *pc = 2; // Fehler: gezeigtes konstantes int kann nicht geändert werden cp = &ci; // Fehler: konstanter Zeiger (auf nicht-konstantes int) kann nicht geändert werden cpc++; // Fehler: konstanter Zeiger (auf konstantes int) kann nicht geändert werden p = pc; // Fehler: Zeiger auf nicht-konstantes int kann nicht auf konstantes int zeigen ppc = &p; // Fehler: Zeiger auf Zeiger auf konstantes int kann nicht auf // Zeiger auf nicht-konstantes int zeigen
Im Allgemeinen folgt die implizite Konvertierung von einem mehrstufigen Zeiger zu einem anderen den Regeln, die in Qualifikationskonvertierungen beschrieben sind.
Zusammengesetzter Zeigertyp
Wenn ein Operand eines Vergleichsoperators oder einer der zweiten und dritten Operanden eines bedingten Operators ein Zeiger oder Zeiger-auf-Mitglied ist, wird ein zusammengesetzter Zeigertyp als gemeinsamer Typ dieser Operanden bestimmt.
Gegeben zwei Operanden
p1
und
p2
mit den Typen
T1
und
T2
jeweils,
können
p1
und
p2
nur dann einen zusammengesetzten Zeigertyp haben, wenn eine der folgenden Bedingungen erfüllt ist:
|
(bis C++14) | ||
|
(seit C++14) |
Der
zusammengesetzte Zeigertyp
C
von
p1
und
p2
wird wie folgt bestimmt:
|
(bis C++11) |
|
(seit C++11) |
- Andernfalls, wenn alle folgenden Bedingungen erfüllt sind:
-
-
T1oderT2ist "Zeiger auf cv1 void ". -
Der andere Typ ist "Zeiger auf
cv2
T", wobeiTein Objekttyp oder void ist.
-
-
Cist "Zeiger auf cv12 void ", wobei cv12 die Vereinigung von cv1 und cv2 ist.
|
(seit C++17) |
- Andernfalls, wenn alle folgenden Bedingungen erfüllt sind:
-
-
T1ist "Zeiger aufC1". -
T2ist "Zeiger aufC2". -
Einer der beiden Typen
C1undC2ist referenzverwandt mit dem anderen.
-
-
Cist-
der
qualifikationskombinierte Typ
von
T1undT2, fallsC1referenzverwandt mitC2ist, oder -
der qualifikationskombinierte Typ von
T2undT1, fallsC2referenzverwandt mitC1ist.
-
der
qualifikationskombinierte Typ
von
|
(seit C++17) |
- Andernfalls, wenn alle folgenden Bedingungen erfüllt sind:
-
-
T1ist "Zeiger auf Element vonC1vom Nicht-FunktionstypM1". -
T2ist "Zeiger auf Element vonC2vom Nicht-FunktionstypM2" -
M1undM2sind identisch bis auf Top-Level CV-Qualifizierungen. -
Einer von
C1undC2ist referenzverwandt mit dem anderen.
-
-
Cist-
der qualifikationskombinierte Typ von
T2undT1, wennC1referenzverwandt zuC2ist, oder -
der qualifikationskombinierte Typ von
T1undT2, wennC2referenzverwandt zuC1ist.
-
der qualifikationskombinierte Typ von
-
Andernfalls, falls
T1undT2ähnliche Typen sind, istCder qualifikationskombinierte Typ vonT1undT2. -
Andernfalls haben
p1
und
p2
keinen zusammengesetzten Zeigertyp, und ein Programm, das die Bestimmung von
Cals solchen Typ erfordert, ist fehlerhaft.
using p = void*; using q = const int*; // Die Bestimmung des zusammengesetzten Zeigertyps von „p“ und „q“ // fällt unter den Fall [„Zeiger auf cv1 void“ und „Zeiger auf cv2 T“]: // cv1 = leer, cv2 = const, cv12 = const // Ersetze „cv12 = const“ in „Zeiger auf cv12 void“: // der zusammengesetzte Zeigertyp ist „const void*“ using pi = int**; using pci = const int**; // Die Bestimmung des zusammengesetzten Zeigertyps von „pi“ und „pci“ // fällt unter den Fall [Zeiger auf ähnliche Typen „C1“ und „C2“]: // C1 = int*, C2 = const int* // es sind referenzverwandte Typen (in beide Richtungen), da sie ähnlich sind // der zusammengesetzte Zeigertyp ist der qualifikationskombinierte Typ // von „p1“ und „pc1“ (oder der von „pci“ und „pi“): „const int**“
Fehlerberichte
Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | Angewendet auf | Verhalten wie veröffentlicht | Korrektes Verhalten |
|---|---|---|---|
| CWG 73 | C++98 |
ein Zeiger auf ein Objekt verglich sich nie gleich
mit einem Zeiger auf das Ende eines Arrays |
für nicht-null und nicht-Funktionszeiger,
vergleiche die Adressen, die sie repräsentieren |
| CWG 903 | C++98 |
jeder integrale konstante Ausdruck, der
zu 0 ausgewertet wurde, war ein Nullzeigerkonstant |
beschränkt auf Integer-
Literale mit Wert 0 |
| CWG 1438 | C++98 |
das Verhalten bei Verwendung eines ungültigen Zeiger-
werts auf irgendeine Weise war undefiniert |
Verhalten außer Dereferenzierung und
Übergabe an Freigabefunktionen sind implementierungsdefiniert |
|
CWG 1512
( N3624 ) |
C++98 |
die Regel für zusammengesetzte Zeigertypen war unvollständig und erlaubte daher
keinen Vergleich zwischen int ** und const int ** |
wurde vervollständigt |
| CWG 2206 | C++98 |
ein Zeiger auf
void
und ein Zeiger auf
Funktion hatten einen zusammengesetzten Zeigertyp |
sie haben keinen solchen Typ |
| CWG 2381 | C++17 |
Funktionszeigerkonvertierungen waren nicht erlaubt
bei der Bestimmung des zusammengesetzten Zeigertyps |
erlaubt |
| CWG 2822 | C++98 |
das Erreichen des Endes der Dauer eines Speicher-
bereichs könnte Zeigerwerte ungültig machen |
Zeigergültigkeit basiert
auf dem Auswertungskontext |
| CWG 2933 | C++98 | Zeiger auf Funktionen waren immer ungültig | sie sind immer gültig |
Siehe auch
|
C-Dokumentation
für
Pointer-Deklaration
|