Namespaces
Variants

std::launder

Von de.cppreference.net
 
 
Dienstprogrammbibliothek
Sprachunterstützung
Typunterstützung (Basistypen, RTTI)
Bibliotheks-Feature-Test-Makros (C++20)
Programm-Dienstprogramme
Variadische Funktionen
Koroutinenunterstützung (C++20)
Vertragsunterstützung (C++26)
Drei-Wege-Vergleich
(C++20)
(C++20)(C++20)(C++20)    
(C++20)(C++20)(C++20)

Allgemeine Dienstprogramme
Relationale Operatoren (veraltet in C++20)
Ganzzahl-Vergleichsfunktionen
(C++20)(C++20)(C++20)    
(C++20)
Tausch und Typoperationen
(C++14)
(C++11)
(C++11)
(C++11)
(C++17)
Allgemeine Vokabular-Typen
(C++11)
(C++17)
(C++17)
(C++17)
(C++11)
(C++17)
(C++23)



 
Speicherverwaltungsbibliothek
Allokatoren
Speicherressourcen
Nicht initialisierter Speicher (bis C++20*)
Garbage-Collector-Unterstützung (bis C++23)
 
 
Definiert in Header <new>
template< class T >
constexpr T* launder( T* p ) noexcept;
(seit C++17)

Devirtualisierungszaun in Bezug auf p. Gibt einen Zeiger auf ein Objekt an derselben Adresse zurück, die p darstellt, wobei das Objekt ein neues Basisklassen-Subobjekt sein kann, dessen abgeleitete Klasse sich von der des ursprünglichen *p-Objekts unterscheidet.

Formal gilt: Gegeben

  • der Zeiger p repräsentiert die Adresse A eines Bytes im Speicher
  • ein Objekt x befindet sich an der Adresse A
  • x ist innerhalb seiner Lebensdauer
  • der Typ von x ist derselbe wie T, wobei cv-Qualifizierer auf jeder Ebene ignoriert werden
  • jedes Byte, das durch das Ergebnis erreichbar wäre, ist durch p erreichbar (Bytes sind durch einen Zeiger erreichbar, der auf ein Objekt y zeigt, wenn diese Bytes innerhalb des Speichers eines Objekts z liegen, das zeiger-unterkonvertierbar mit y ist, oder innerhalb des unmittelbar umschließenden Arrays, von dem z ein Element ist).

Dann gibt std::launder(p) einen Wert vom Typ T* zurück, der auf das Objekt x zeigt. Andernfalls ist das Verhalten undefiniert.

Das Programm ist fehlerhaft (ill-formed), wenn T ein Funktionstyp oder (möglicherweise cv-qualifiziert) void ist.

std::launder darf in einem Core-Konstantenausdruck verwendet werden, genau dann, wenn der (konvertierte) Wert seines Arguments anstelle des Funktionsaufrufs verwendet werden darf. Mit anderen Worten, std::launder lockert keine Einschränkungen bei der Konstantenauswertung.

Hinweise

std::launder hat keine Auswirkung auf sein Argument. Sein Rückgabewert muss verwendet werden, um auf das Objekt zuzugreifen. Daher ist es immer ein Fehler, den Rückgabewert zu verwerfen.

Typische Anwendungen von std::launder umfassen:

  • Erhalten eines Zeigers auf ein Objekt, das im Speicher eines bestehenden Objekts desselben Typs erstellt wurde, wobei Zeiger auf das alte Objekt nicht wiederverwendet werden können (beispielsweise weil eines der Objekte ein Basisklassen-Subobjekt ist);
  • Erhalten eines Zeigers auf ein Objekt, das durch Placement- new erstellt wurde, aus einem Zeiger auf ein Objekt, das den Speicher für dieses Objekt bereitstellt.

Die reachability -Einschränkung stellt sicher, dass std::launder nicht verwendet werden kann, um auf Bytes zuzugreifen, die nicht durch den ursprünglichen Zeiger erreichbar sind, und stört dadurch die Escape-Analyse des Compilers.

int x[10];
auto p = std::launder(reinterpret_cast<int(*)[10]>(&x[0])); // OK
int x2[2][10];
auto p2 = std::launder(reinterpret_cast<int(*)[10]>(&x2[0][0]));
// Undefiniertes Verhalten: x2[1] wäre über den resultierenden Zeiger auf x2[0] erreichbar
// ist aber von der Quelle aus nicht erreichbar
struct X { int a[10]; } x3, x4[2]; // Standard-Layout; ohne Padding angenommen
auto p3 = std::launder(reinterpret_cast<int(*)[10]>(&x3.a[0])); // OK
auto p4 = std::launder(reinterpret_cast<int(*)[10]>(&x4[0].a[0]));
// Undefiniertes Verhalten: x4[1] wäre über den resultierenden Zeiger auf x4[0].a
// (der zeigerinterkonvertierbar mit x4[0] ist) erreichbar, ist aber von der Quelle aus nicht erreichbar
struct Y { int a[10]; double y; } x5;
auto p5 = std::launder(reinterpret_cast<int(*)[10]>(&x5.a[0]));
// Undefiniertes Verhalten: x5.y wäre über den resultierenden Zeiger auf x5.a
// erreichbar, ist aber von der Quelle aus nicht erreichbar

Beispiel

#include <cassert>
#include <cstddef>
#include <new>
struct Base
{
    virtual int transmogrify();
};
struct Derived : Base
{
    int transmogrify() override
    {
        new(this) Base;
        return 2;
    }
};
int Base::transmogrify()
{
    new(this) Derived;
    return 1;
}
static_assert(sizeof(Derived) == sizeof(Base));
int main()
{
    // Fall 1: Das neue Objekt konnte nicht transparent ersetzt werden, weil
    // es ein Basis-Subobjekt ist, aber das alte Objekt ein vollständiges Objekt ist.
    Base base;
    int n = base.transmogrify();
    // int m = base.transmogrify(); // undefiniertes Verhalten
    int m = std::launder(&base)->transmogrify(); // OK
    assert(m + n == 3);
    // Fall 2: Zugriff auf ein neues Objekt, dessen Speicher
    // durch ein Byte-Array bereitgestellt wird, über einen Zeiger auf das Array.
    struct Y { int z; };
    alignas(Y) std::byte s[sizeof(Y)];
    Y* q = new(&s) Y{2};
    const int f = reinterpret_cast<Y*>(&s)->z; // Klassenmember-Zugriff ist undefiniertes
                                               // Verhalten: reinterpret_cast<Y*>(&s)
                                               // hat den Wert "Zeiger auf s" und zeigt
                                               // nicht auf ein Y-Objekt
    const int g = q->z; // OK
    const int h = std::launder(reinterpret_cast<Y*>(&s))->z; // OK
    [](...){}(f, g, h); // erzeugt [[maybe_unused]]-Effekt
}

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
LWG 2859 C++17 Definition von reachable berücksichtigte keine Pointer-Arithmetik
von pointer-interconvertiblem Objekt
eingeschlossen
LWG 3495 C++17 std::launder könnte Pointer auf inaktives
Mitglied in konstantem Ausdruck dereferenzierbar machen
verboten