c++ - entre - ¿Cuál es el propósito de std:: launder?
c++20 (1)
std::launder
tiene un nombre adecuado, aunque solo si sabes para qué sirve.
Realiza
lavado de memoria
.
Considere el ejemplo en el documento:
struct X { const int n; };
union U { X x; float f; };
...
U u = {{ 1 }};
Esa declaración realiza una inicialización agregada, inicializando el primer miembro de
U
con
{1}
.
Como
n
es una variable
const
, el compilador puede suponer que
uxn
siempre
será 1.
Entonces, ¿qué sucede si hacemos esto:
X *p = new (&u.x) X {2};
Como
X
es trivial, no necesitamos destruir el objeto antiguo antes de crear uno nuevo en su lugar, por lo que este es un código perfectamente legal.
El nuevo objeto tendrá su
n
miembro será 2.
Entonces dime ... ¿
uxn
volverá?
La respuesta obvia será 2. Pero eso está mal, porque el compilador puede suponer que una variable
const
verdaderamente (no solo una
const&
, sino una variable de objeto
declarada
const
)
nunca cambiará
.
Pero lo acabamos de cambiar.
[basic.life]/8
explica las circunstancias en las que está bien acceder al objeto recién creado a través de variables / punteros / referencias al antiguo.
Y tener un miembro
const
es uno de los factores descalificadores.
Entonces ... ¿cómo podemos hablar sobre
uxn
correctamente?
Tenemos que lavar nuestra memoria:
assert(*std::launder(&u.x.n) == 2); //Will be true.
El lavado de dinero se utiliza para evitar que las personas rastreen de dónde obtuvo su dinero. El lavado de memoria se usa para evitar que el compilador rastree de dónde obtuvo su objeto, lo que lo obliga a evitar cualquier optimización que ya no se aplique.
Otro de los factores descalificadores es si cambia el tipo de objeto.
std::launder
puede ayudar aquí:
aligned_storage<sizeof(int), alignof(int)>::type data;
new(&data) int;
int *p = std::launder(reinterpret_cast<int*>(&data));
[basic.life]/8
nos dice que, si asigna un nuevo objeto en el almacenamiento del antiguo, no puede acceder al nuevo objeto mediante punteros al antiguo.
launder
nos permite
launder
eso.
P0137
presenta la plantilla de función
std::launder
y realiza muchos, muchos cambios al estándar en las secciones relativas a uniones, vida útil y punteros.
¿Cuál es el problema que este documento está resolviendo?
¿Cuáles son los cambios en el idioma que debo tener en cuenta?
¿Y qué estamos
launder
?