Namensräume
Varianten
Aktionen

Zeigerdeklaration

Von cppreference.com
< cpp‎ | Sprache
 
 
C++ Sprache
Allgemeine Themen
Kontrollfluss
Bedingte Ausführungsaussagen
if
Iterationsanweisungen (Schleifen)
for
Bereichs-for (C++11)
Sprunganweisungen
Funktionen
Funktionsdeklaration
Lambda-Funktionsausdruck
inline-Spezifizierer
Dynamische Ausnahmespezifikationen (bis C++17*)
noexcept-Spezifizierer (C++11)
Ausnahmen
Namensräume
Typen
Spezifizierer
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Speicherdauer-Spezifizierer
Initialisierung
Ausdrücke
Alternative Darstellungen
Literale
Boolesch - Ganzzahl - Gleitkommazahl
Zeichen - String - nullptr (C++11)
Benutzerdefinierte (C++11)
Dienstprogramme
Attribute (C++11)
Typen
typedef-Deklaration
Typalias-Deklaration (C++11)
Umwandlungen
Speicherzuweisung
Klassen
Klassenspezifische Funktionseigenschaften
explicit (C++11)
static

Spezielle Member-Funktionen
Templates
Sonstiges
 
 

Deklariert eine Variable eines Zeiger- oder Zeiger-auf-Mitglied-Typs.

Inhalt

[bearbeiten] Syntax

Eine Zeigerdeklaration ist jede einfache Deklaration, deren Deklarator die Form hat

* attr (optional) cv (optional) Deklarator (1)
verschachtelter-name-spezifizierer * attr (optional) cv (optional) Deklarator (2)
1) Zeiger-Deklarator: die Deklaration S* D; deklariert D als Zeiger auf den durch die Deklarationsspezifizierersequenz S bestimmten Typ.
2) Zeiger-auf-Mitglied-Deklarator: die Deklaration S C::* D; deklariert D als Zeiger auf ein nicht-statisches Mitglied von C vom Typ, der durch die Deklarationsspezifizierersequenz S bestimmt wird.
nested-name-specifier - eine Sequenz von Namen und Bereichsauflösungsoperatoren ::
attr - (seit C++11) eine Liste von Attributen
cv - const/volatile-Qualifikation, die für den zu deklarierenden Zeiger gilt (nicht für den auf den Typ zeigenden, dessen Qualifikationen Teil der Deklarationsspezifizierersequenz sind)
Deklarator - jeder Deklarator außer einem Referenzdeklarator (es gibt keine Zeiger auf Referenzen). Es kann ein weiterer Zeiger-Deklarator sein (Zeiger auf Zeiger sind erlaubt)

Es gibt keine Zeiger auf Referenzen und keine Zeiger auf Bitfelder. Typischerweise schließen Erwähnungen von "Zeigern" ohne weitere Erläuterung keine Zeiger auf (nicht-statische) Mitglieder ein.

[bearbeiten] Zeiger

Jeder Wert eines Zeigertyps 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 das Ende eines Objekts repräsentiert die Adresse des ersten Bytes im Speicher nach dem Ende des vom Objekt belegten Speichers.

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;   // value of px is "pointer to c.x"
int* pxe= px + 1; // value of pxe is "pointer past the end of c.x"
int* py = &c.y;   // value of py is "pointer to c.y"
 
assert(pxe == py); // == tests if two pointers represent the same address
                   // may or may not fire
 
*pxe = 1; // undefined behavior even if the assertion does not fire

Indirektion über einen ungültigen Zeigerwert und Übergabe eines ungültigen Zeigerwerts an eine Freigabefunktion haben undefiniertes Verhalten. Jede andere Verwendung eines ungültigen Zeigerwerts hat implementierungsdefiniertes Verhalten. Einige Implementierungen definieren möglicherweise, dass das Kopieren eines ungültigen Zeigerwerts zu einem systemgenerierten Laufzeitfehler führt.

[bearbeiten] Objektzeiger

Ein Zeiger auf ein Objekt kann mit dem Rückgabewert des Adressoperator initialisiert werden, der auf einen Ausdruck von Objekttyp angewendet wird, einschließlich eines anderen Zeigertyps.

int n;
int* np = &n;          // pointer to int
int* const* npp = &np; // non-const pointer to const pointer to non-const int
 
int a[2];
int (*ap)[2] = &a;     // pointer to array of int
 
struct S { int n; };
 
S s = {1};
int* sp = &s.n;        // pointer to the int that is a member of s

Zeiger können Operanden des eingebauten Indirektionsoperators (unäres operator*) sein, der den lvalue-Ausdruck zurückgibt, der das referenzierte Objekt identifiziert.

int n;
int* p = &n;     // pointer to n
int& r = *p;     // reference is bound to the lvalue expression that identifies n
r = 7;           // stores the int 7 in n
std::cout << *p; // lvalue-to-rvalue implicit conversion reads the value from n

Zeiger auf Klassenobjekte können auch als linke Operanden der Member-Zugriffsoperatoren operator-> und operator->* auftreten.

Aufgrund der impliziten Konvertierung von Arrays zu Zeigern kann ein Zeiger auf das erste Element eines Arrays mit einem Ausdruck von Arraytyp initialisiert werden.

int a[2];
int* p1 = a; // pointer to the first element a[0] (an int) of the array a
 
int b[6][3][8];
int (*p2)[3][8] = b; // pointer to the first element b[0] of the array b,
                     // which is an array of 3 arrays of 8 ints

Aufgrund der impliziten Konvertierung von Basisklassen zu abgeleiteten Klassen 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;

Wenn Derived polymorph ist, kann ein solcher Zeiger verwendet werden, um virtuelle Funktionsaufrufe durchzuführen.

Bestimmte Additions-, Subtraktions-, Inkrement- und Dekrementoperatoren sind für Zeiger auf Array-Elemente definiert: solche Zeiger erfüllen die LegacyRandomAccessIterator-Anforderungen und ermöglichen es den C++-Bibliotheks-Algorithmen, mit rohen Arrays zu arbeiten.

Vergleichsoperatoren sind für Zeiger auf Objekte in einigen Situationen definiert: Zwei Zeiger, die dieselbe Adresse repräsentieren, vergleichen sich gleich, zwei Nullzeigerwerte vergleichen sich gleich, Zeiger auf Elemente desselben Arrays vergleichen sich genauso wie die Array-Indizes dieser Elemente, und Zeiger auf nicht-statische Datenmember mit demselben Mitgliederzugriff vergleichen sich in der Reihenfolge der Deklaration dieser Member.

Viele Implementierungen bieten auch eine strikte totale Ordnung von Zeigern beliebigen Ursprungs, z. B. wenn sie als Adressen innerhalb eines kontinuierlichen virtuellen Adressraums implementiert sind. Implementierungen, die dies nicht tun (z. B. wenn nicht alle Bits des Zeigers Teil einer Speicheradresse sind und für den Vergleich ignoriert werden müssen, oder eine zusätzliche Berechnung erforderlich ist oder anderweitig Zeiger und Integer keine 1:1-Beziehung darstellen), bieten eine Spezialisierung von std::less für Zeiger, die diese Garantie hat. Dies ermöglicht die Verwendung aller Zeiger beliebigen Ursprungs als Schlüssel in Standard-Assoziativcontainern wie std::set oder std::map.

[bearbeiten] Zeiger auf void

Ein Zeiger auf ein Objekt beliebigen Typs kann implizit konvertiert werden in einen Zeiger auf einen (möglicherweise cv-qualifizierten) void; der Zeigerwert bleibt unverändert. Die umgekehrte Konvertierung, die eine static_cast oder explizite Umwandlung erfordert, ergibt den ursprünglichen Zeigerwert.

int n = 1;
int* p1 = &n;
void* pv = p1;
int* p2 = static_cast<int*>(pv);
std::cout << *p2 << '\n'; // prints 1

Wenn der ursprüngliche Zeiger auf ein Basisklassen-Subobjekt innerhalb eines Objekts eines polymorphen Typs zeigt, kann dynamic_cast verwendet werden, um einen void* zu erhalten, der auf das vollständige Objekt des abgeleitetsten Typs zeigt.

Zeiger auf void haben dieselbe 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 eine vom Benutzer bereitgestellte Callback-Funktion, die zwei const void* Argumente akzeptiert. pthread_create erwartet eine vom Benutzer bereitgestellte Callback-Funktion, die void* akzeptiert und zurückgibt. In allen Fällen liegt es in der Verantwortung des Aufrufers, den Zeiger vor der Verwendung in den korrekten Typ umzuwandeln.

[bearbeiten] Funktionszeiger

Ein Zeiger auf eine Funktion kann mit der Adresse einer Nicht-Member-Funktion oder einer statischen Member-Funktion initialisiert werden. Aufgrund der impliziten Konvertierung von Funktionen zu Zeigern ist der Adressoperator optional.

void f(int);
void (*p1)(int) = &f;
void (*p2)(int) = f; // same as &f

Im Gegensatz zu Funktionen oder Referenzen auf Funktionen sind Funktionszeiger Objekte und können daher in Arrays gespeichert, kopiert, zugewiesen usw. werden.

void (a[10])(int);  // Error: array of functions
void (&a[10])(int); // Error: array of references
void (*a[10])(int); // OK: array of pointers to functions

Hinweis: Deklarationen, die Funktionszeiger beinhalten, können oft durch Typ-Aliase vereinfacht werden.

using F = void(int); // named type alias to simplify declarations
F a[10];  // Error: array of functions
F& a[10]; // Error: array of references
F* a[10]; // OK: array of pointers to functions

Ein Funktionszeiger kann als linker Operand des Funktionsaufrufoperators verwendet werden, dies ruft die referenzierte Funktion auf.

int f(int n)
{
    std::cout << n << '\n';
    return n * n;
}
 
int main()
{
    int (*p)(int) = f;
    int x = p(7);
}

Dereferenzieren eines Funktionszeigers ergibt den lvalue, der die referenzierte Funktion identifiziert.

int f();
int (*p)() = f;  // pointer p is pointing to f
int (&r)() = *p; // the lvalue that identifies f is bound to a reference
r();             // function f invoked through lvalue reference
(*p)();          // function f invoked through the function lvalue
p();             // function f invoked directly through the pointer

Ein Funktionszeiger kann aus einem Überladungsset initialisiert werden, das Funktionen, spezialisierte Funktionsvorlagen und Funktionsvorlagen enthalten kann, wenn nur eine Überladung dem Typ des Zeigers entspricht (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; // instantiates and selects f<int>
}

Gleichheitsvergleichsoperatoren sind für Funktionszeiger definiert (sie vergleichen sich gleich, wenn sie auf dieselbe Funktion zeigen).

[bearbeiten] Zeiger auf Mitglieder

[bearbeiten] Zeiger auf Datenmember

Ein Zeiger auf ein nicht-statisches Objektmitglied m, das ein Mitglied der Klasse C ist, kann exakt mit dem Ausdruck &C::m initialisiert werden. Ausdrücke wie &(C::m) oder &m innerhalb einer Member-Funktion von C bilden keine Zeiger auf Mitglieder.

Ein solcher Zeiger kann als rechter Operand der Zeiger-auf-Mitglied-Zugriffsoperatoren operator.* und operator->* verwendet werden.

struct C { int m; };
 
int main()
{
    int C::* p = &C::m;          // pointer to data member m of class C
    C c = {7};
    std::cout << c.*p << '\n';   // prints 7
    C* cp = &c;
    cp->m = 10;
    std::cout << cp->*p << '\n'; // prints 10
}

Ein Zeiger auf ein Datenmitglied einer zugänglichen, eindeutigen, nicht-virtuellen Basisklasse kann implizit konvertiert werden in einen 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'; // prints 1 1
}

Eine Konvertierung in die entgegengesetzte Richtung, von einem Zeiger auf ein Datenmitglied einer abgeleiteten Klasse zu einem Zeiger auf ein Datenmitglied einer eindeutigen, nicht-virtuellen Basisklasse, ist mit static_cast und expliziter Umwandlung erlaubt, auch wenn die Basisklasse dieses Mitglied nicht hat (aber die abgeleitetste Klasse hat es, wenn der Zeiger für den Zugriff verwendet wird).

struct Base {};
struct Derived : Base { int m; };
 
int main()
{
    int Derived::* dp = &Derived::m;
    int Base::* bp = static_cast<int Base::*>(dp);
 
    Derived d;
    d.m = 7;
    std::cout << d.*bp << '\n'; // okay: prints 7
 
    Base b;
    std::cout << b.*bp << '\n'; // undefined behavior
}

Der auf den Typ zeigende Teil eines Zeigers auf ein Mitglied kann selbst ein Zeiger auf ein 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;
    // const pointer to non-const member
    int A::* const p;
};
 
int main()
{
    // non-const pointer to data member which is a const pointer to non-const member
    int A::* const A::* p1 = &A::p;
 
    const A a = {1, &A::m};
    std::cout << a.*(a.*p1) << '\n'; // prints 1
 
    // regular non-const pointer to a const pointer-to-member
    int A::* const* p2 = &a.p;
    std::cout << a.**p2 << '\n'; // prints 1
}

[bearbeiten] Zeiger auf Memberfunktionen

Ein Zeiger auf eine nicht-statische Memberfunktion f, die ein Mitglied der Klasse C ist, kann exakt mit dem Ausdruck &C::f initialisiert werden. Ausdrücke wie &(C::f) oder &f innerhalb einer Member-Funktion von C bilden keine Zeiger auf Memberfunktionen.

Ein solcher Zeiger kann als rechter Operand der Zeiger-auf-Mitglied-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; // pointer to member function f of class C
    C c;
    (c.*p)(1);                  // prints 1
    C* cp = &c;
    (cp->*p)(2);                // prints 2
}


Ein Zeiger auf eine Memberfunktion einer Basisklasse kann implizit konvertiert werden in einen Zeiger 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);
}

Eine Konvertierung 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 mit static_cast und expliziter Umwandlung erlaubt, auch wenn die Basisklasse diese Memberfunktion nicht hat (aber die abgeleitetste Klasse hat 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); // okay: prints 1
 
    Base b;
    (b.*bp)(2); // undefined behavior
}

Zeiger auf Memberfunktionen können als Callbacks oder als Funktions-Objekte 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

[bearbeiten] Nullzeiger

Zeiger jedes Typs haben einen speziellen Wert, der als Nullzeigerwert dieses Typs bekannt ist. Ein Zeiger, dessen Wert null ist, zeigt nicht auf ein Objekt oder eine Funktion (das Verhalten des Dereferenzierens eines Nullzeigers ist undefiniert) und vergleicht sich gleich mit allen Zeigern desselben Typs, deren Wert ebenfalls null ist.

Eine Nullzeigerkonstante kann verwendet werden, um einen Zeiger auf null zu initialisieren oder um den Nullwert einem vorhandenen Zeiger zuzuweisen; sie ist einer der folgenden Werte:

  • Ein Ganzzahl-Literal mit dem Wert Null.
(seit C++11)

Das Makro NULL kann ebenfalls verwendet werden, es expandiert zu einer implementierungsdefinierten Nullzeigerkonstante.

Null-Initialisierung und Wert-Initialisierung initialisieren Zeiger ebenfalls mit ihren Nullwerten.

Nullzeiger können verwendet werden, um die Abwesenheit eines Objekts anzuzeigen (z. B. std::function::target()) oder als Indikatoren für andere Fehlerbedingungen (z. B. dynamic_cast). Im Allgemeinen muss eine Funktion, die ein Zeigerargument empfängt, fast immer überprüfen, ob der Wert null ist, und diesen Fall anders behandeln (z. B. bewirkt der delete-Ausdruck nichts, wenn ein Nullzeiger übergeben wird).

[bearbeiten] Ungültige Zeiger

Ein Zeigerwert p ist im Kontext einer Auswertung e gültig, 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 liegt innerhalb der Lebensdauer 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, the evaluation “*local_ptr” is
                    // in the storage duration of “obj”
 
    return local_ptr;
}
 
int* ptr = f();  // the storage duration of “obj” is expired,
                 // therefore “ptr” is an invalid pointer in the following contexts
 
int* copy = ptr; // implementation-defined behavior
*ptr = 2;        // undefined behavior: indirection of an invalid pointer
delete ptr;      // undefined behavior: deallocating storage from an invalid pointer

[bearbeiten] Constness

  • Wenn cv vor * in der Zeigerdeklaration erscheint, ist es Teil der Deklarationsspezifizierersequenz und gilt für das referenzierte Objekt.
  • Wenn cv nach * in der Zeigerdeklaration erscheint, ist es Teil des Deklarators und gilt für den zu deklarierenden Zeiger.
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 is a non-const pointer to const int
// cpc is a const pointer to const int
// ppc is a non-const pointer to non-const pointer to const int
const int ci = 10, *pc = &ci, *const cpc = pc, **ppc;
// p is a non-const pointer to non-const int
// cp is a const pointer to non-const int
int i, *p, *const cp = &i;
 
i = ci;    // okay: value of const int copied into non-const int
*cp = ci;  // okay: non-const int (pointed-to by const pointer) can be changed
pc++;      // okay: non-const pointer (to const int) can be changed
pc = cpc;  // okay: non-const pointer (to const int) can be changed
pc = p;    // okay: non-const pointer (to const int) can be changed
ppc = &pc; // okay: address of pointer to const int is pointer to pointer to const int
 
ci = 1;    // error: const int cannot be changed
ci++;      // error: const int cannot be changed
*pc = 2;   // error: pointed-to const int cannot be changed
cp = &ci;  // error: const pointer (to non-const int) cannot be changed
cpc++;     // error: const pointer (to const int) cannot be changed
p = pc;    // error: pointer to non-const int cannot point to const int
ppc = &p;  // error: pointer to pointer to const int cannot point to
           // pointer to non-const int

Im Allgemeinen folgt die implizite Konvertierung von einem mehrstufigen Zeiger zu einem anderen den Regeln, die unter Qualifikationskonvertierungen beschrieben sind.

[bearbeiten] Zusammengesetzter Zeigertyp

Wenn ein Operand eines Vergleichsoperators oder eines 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 seien zwei Operanden p1 und p2 mit den Typen T1 bzw. T2. p1 und p2 können nur dann einen zusammengesetzten Zeigertyp haben, wenn eine der folgenden Bedingungen erfüllt ist:

  • p1 und p2 sind beides Zeiger.
  • Einer der Operanden p1 und p2 ist ein Zeiger und der andere Operand ist eine Nullzeigerkonstante.
  • p1 und p2 sind beides Nullzeigerkonstanten, und mindestens einer der Typen T1 und T2 ist ein nicht-ganzzahliger Typ.
(seit C++11)
(bis C++14)
  • Mindestens einer der Typen T1 und T2 ist ein Zeigertyp, ein Zeiger-auf-Mitglied-Typ oder std::nullptr_t.
(seit C++14)

Der zusammengesetzte Zeigertyp C von p1 und p2 wird wie folgt bestimmt:

  • Wenn p1 eine Nullzeigerkonstante ist, ist C T2.
  • Wenn andernfalls p2 eine Nullzeigerkonstante ist, ist C T1.
(bis C++11)
  • Wenn p1 und p2 beides Nullzeigerkonstanten sind, ist C std::nullptr_t.
  • Wenn andernfalls p1 eine Nullzeigerkonstante ist, ist C T2.
  • Wenn andernfalls p2 eine Nullzeigerkonstante ist, ist C T1.
(seit C++11)
  • Wenn andernfalls alle folgenden Bedingungen erfüllt sind:
  • T1 oder T2 ist „Zeiger auf cv1 void“.
  • Der andere Typ ist „Zeiger auf cv2 T“, wobei T ein Objekttyp oder void ist.
C ist „Zeiger auf cv12 void“, wobei cv12 die Vereinigung von cv1 und cv2 ist.
  • Wenn andernfalls alle folgenden Bedingungen erfüllt sind:
  • T1 oder T2 ist „Zeiger auf Funktionstyp F1“.
  • Der andere Typ ist „Zeiger auf noexcept-Funktionstyp F2“.
  • F1 und F2 sind bis auf noexcept gleich.
C ist „Zeiger auf F1“.
(seit C++17)
  • Wenn andernfalls alle folgenden Bedingungen erfüllt sind:
  • T1 ist „Zeiger auf C1“.
  • T2 ist „Zeiger auf C2“.
  • Einer der Typen C1 und C2 ist referenzbezogen zum anderen.
C ist
  • der qualifikationskombinierte Typ von T1 und T2, wenn C1 referenzbezogen zu C2 ist, oder
  • der qualifikationskombinierte Typ von T2 und T1, wenn C2 referenzbezogen zu C1 ist.
  • Wenn andernfalls alle folgenden Bedingungen erfüllt sind:
  • T1 oder T2 ist „Zeiger auf Mitglied von C1 vom Funktionstyp F1“.
  • Der andere Typ ist „Zeiger auf Mitglied von C2 vom noexcept-Funktionstyp F2“.
  • Einer der Typen C1 und C2 ist referenzbezogen zum anderen.
  • F1 und F2 sind bis auf noexcept gleich.
C ist
  • „Zeiger auf Mitglied von C2 vom Typ F1“, wenn C1 referenzbezogen zu C2 ist, oder
  • „Zeiger auf Mitglied von C1 vom Typ F1“, wenn C2 referenzbezogen zu C1 ist.
(seit C++17)
  • Wenn andernfalls alle folgenden Bedingungen erfüllt sind:
  • T1 ist „Zeiger auf Mitglied von C1 vom Nicht-Funktionstyp M1“.
  • T2 ist „Zeiger auf Mitglied von C2 vom Nicht-Funktionstyp M2
  • M1 und M2 sind gleich, abgesehen von Top-Level-cv-Qualifikationen.
  • Einer der Typen C1 und C2 ist referenzbezogen zum anderen.
C ist
  • der qualifikationskombinierte Typ von T2 und T1, wenn C1 referenzbezogen zu C2 ist, oder
  • der qualifikationskombinierte Typ von T1 und T2, wenn C2 referenzbezogen zu C1 ist.
  • Wenn andernfalls, wenn T1 und T2 ähnliche Typen sind, ist C der qualifikationskombinierte Typ von T1 und T2.
  • Andernfalls haben p1 und p2 keinen zusammengesetzten Zeigertyp; ein Programm, das die Bestimmung eines solchen Typs C erfordert, ist ill-formed.
using p = void*;
using q = const int*;
// The determination of the composite pointer type of “p” and “q”
// falls into the [“pointer to cv1 void” and “pointer to cv2 T”] case:
// cv1 = empty, cv2 = const, cv12 = const
// substitute “cv12 = const” into “pointer to cv12 void”:
// the composite pointer type is “const void*”
 
using pi = int**;
using pci = const int**;
// The determination of the composite pointer type of “pi” and “pci”
// falls into the [pointers to similar types “C1” and “C2”] case:
// C1 = int*, C2 = const int*
// they are reference-related types (in both direction) because they are similar
// the composite pointer type is the qualification-combined type
// of “p1” and “pc1” (or that of “pci” and “pi”): “const void* const *”

[bearbeiten] Defect reports

Die folgenden Verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.

DR angewendet auf Verhalten wie veröffentlicht Korrigiertes Verhalten
CWG 73 C++98 Ein Zeiger auf ein Objekt vergleicht sich nie gleich
mit einem Zeiger auf das Ende eines Arrays
für nicht-null und nicht-Funktionszeiger,
vergleiche die von ihnen repräsentierten Adressen
CWG 903 C++98 jeder Ganzzahl-Konstantausdruck, der
zu 0 ausgewertet wird, war eine Nullzeigerkonstante
beschränkt auf Ganzzahl
Literale mit Wert 0
CWG 1438 C++98 Das Verhalten bei der Verwendung eines ungültigen Zeiger
Wertes in irgendeiner Weise war undefiniert
Verhalten außer Indirektion und
Übergabe an Freigabefunktionen
sind implementierungsdefiniert
CWG 1512
(N3624)
C++98 Die Regel des zusammengesetzten Zeigertyps war unvollständig und damit
erlaubte keinen Vergleich zwischen int** und const int**
vollständig gemacht
CWG 2206 C++98 Ein Zeiger auf void und ein Zeiger auf
eine Funktion hatten einen zusammengesetzten Zeigertyp
sie haben keinen solchen Typ
CWG 2381 C++17 Funktionszeiger-Konvertierungen waren nicht erlaubt
bei der Bestimmung des zusammengesetzten Zeigertyps
erlaubt
CWG 2822 C++98 Erreichen des Endes der Lebensdauer eines Speicherbereichs
könnte Zeigerwerte ungültig machen
Zeigergültigkeit basiert
auf dem Auswertungskontext
CWG 2933 C++98 Funktionszeiger waren immer ungültig sie sind immer gültig

[bearbeiten] Siehe auch

C-Dokumentation für Zeigerdeklaration