Namensräume
Varianten
Aktionen

std::launder

Von cppreference.com
< cpp‎ | utility
 
 
Dienstprogramm-Bibliotheken
Sprachunterstützung
Typunterstützung (Basistypen, RTTI)
Bibliotheks-Feature-Test-Makros (C++20)
Programm-Dienstprogramme
Variadische Funktionen
Coroutine-Unterstü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 Hilfsmittel
Relationale Operatoren (in C++20 veraltet)
 
Speicherverwaltungsbibliothek
(nur Exposition*)
Algorithmen für uninitialisierten Speicher
(C++17)
(C++17)
(C++17)
Beschränkte uninitialisierte
Speicher-Algorithmen
C-Bibliothek

Allocatoren
Speicherressourcen
Unterstützung für Garbage Collection
(C++11)(bis C++23)
(C++11)(bis C++23)
(C++11)(bis C++23)
(C++11)(bis C++23)
(C++11)(bis C++23)
(C++11)(bis C++23)
Uninitialisierter Speicher
Explizites Lebenszeitmanagement
 
 
Definiert im Header <new>
template< class T >
constexpr T* launder( T* p ) noexcept;
(seit C++17)

Devirtualisierungs-Zaun (fence) in Bezug auf p. Gibt einen Zeiger auf ein Objekt an derselben Adresse zurück, die p darstellt, wobei das Objekt ein neues Basiklassen-Subobjekt sein kann, dessen am höchsten abgeleitetes Objekt von dem des ursprünglichen *p-Objekts abweicht.

Formell, gegeben

  • der Zeiger p stellt die Adresse A eines Bytes im Speicher dar
  • ein Objekt x befindet sich an der Adresse A
  • x befindet sich innerhalb seiner Lebensdauer
  • der Typ von x ist derselbe wie T, wobei cv-Qualifizierer auf jeder Ebene ignoriert werden
  • jedes Byte, das über das Ergebnis erreichbar wäre, ist über p erreichbar (Bytes sind über einen Zeiger erreichbar, der auf ein Objekt y zeigt, wenn diese Bytes sich innerhalb des Speichers eines Objekts z befinden, das zu y zeiger-konvertierbar ist, oder innerhalb des unmittelbar umschließenden Arrays, dessen Element z 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 schlecht formuliert, wenn T ein Funktionstyp oder (möglicherweise cv-qualifiziertes) void ist.

std::launder darf in einem Kern-Konstantausdruck verwendet werden, wenn und nur wenn der (konvertierte) Wert seines Arguments anstelle des Funktionsaufrufs verwendet werden kann. Mit anderen Worten, std::launder lockert die Einschränkungen bei der Konstantenauswertung nicht.

[bearbeiten] Anmerkungen

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 Verwendungen von std::launder umfassen

  • Einen Zeiger auf ein Objekt zu erhalten, das im Speicher eines vorhandenen Objekts desselben Typs erstellt wurde, wobei Zeiger auf das alte Objekt nicht wiederverwendet werden können (zum Beispiel, weil ein Objekt ein Basiklassen-Subobjekt ist);
  • Einen Zeiger auf ein Objekt zu erhalten, das durch Placement new aus einem Zeiger auf ein Objekt erstellt wurde, das Speicher für dieses Objekt bereitstellt.

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

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]));
// Undefined behavior: x2[1] would be reachable through the resulting pointer to x2[0]
// but is not reachable from the source
 
struct X { int a[10]; } x3, x4[2]; // standard layout; assume no padding
auto p3 = std::launder(reinterpret_cast<int(*)[10]>(&x3.a[0])); // OK
auto p4 = std::launder(reinterpret_cast<int(*)[10]>(&x4[0].a[0]));
// Undefined behavior: x4[1] would be reachable through the resulting pointer to x4[0].a
// (which is pointer-interconvertible with x4[0]) but is not reachable from the source
 
struct Y { int a[10]; double y; } x5;
auto p5 = std::launder(reinterpret_cast<int(*)[10]>(&x5.a[0]));
// Undefined behavior: x5.y would be reachable through the resulting pointer to x5.a
// but is not reachable from the source

[bearbeiten] 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()
{
    // Case 1: the new object failed to be transparently replaceable because
    // it is a base subobject but the old object is a complete object.
    Base base;
    int n = base.transmogrify();
    // int m = base.transmogrify(); // undefined behavior
    int m = std::launder(&base)->transmogrify(); // OK
    assert(m + n == 3);
 
    // Case 2: access to a new object whose storage is provided
    // by a byte array through a pointer to the 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; // Class member access is undefined
                                               // behavior: reinterpret_cast<Y*>(&s)
                                               // has value "pointer to s" and does
                                               // not point to a Y object
    const int g = q->z; // OK
    const int h = std::launder(reinterpret_cast<Y*>(&s))->z; // OK
 
    [](...){}(f, g, h); // evokes [[maybe_unused]] effect
}

[bearbeiten] Fehlerberichte

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

DR angewendet auf Verhalten wie veröffentlicht Korrigiertes Verhalten
LWG 2859 C++17 Definition von *erreichbar* berücksichtigte keinen Zeiger
Arithmetik von zeiger-konvertierbaren Objekten
enthalten
LWG 3495 C++17 std::launder könnte Zeiger auf einen inaktiven
Mitglied-Dereferenzierung in einem Konstantausdruck
verbieten