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
haciendo?
std::launder
?std::launder
se utiliza para "obtener un puntero a un objeto creado en el almacenamiento ocupado por un objeto existente del mismo tipo, incluso si tiene miembros constantes o de referencia".Respuestas:
std::launder
tiene un nombre adecuado, aunque solo si sabes para qué sirve. Realiza lavado de memoria .Considere el ejemplo en el documento:
Esa declaración realiza una inicialización agregada, inicializando el primer miembro de
U
with{1}
.Debido a que
n
es unaconst
variable, el compilador es libre de asumir queu.x.n
debe siempre ser 1.Entonces, ¿qué sucede si hacemos esto?
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á sun
miembro 2.Entonces dime ... ¿qué volverá
u.x.n
?La respuesta obvia será 2. Pero eso está mal, porque el compilador puede asumir que una
const
variable verdaderamente (no solo unaconst&
, sino una variable de objeto declaradaconst
) 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
const
miembro es uno de los factores descalificadores.Entonces ... ¿cómo podemos hablar
u.x.n
adecuadamente?Tenemos que lavar nuestra memoria:
El lavado de dinero se utiliza para evitar que las personas rastreen de dónde obtuvo su dinero. El lavado de memoria se utiliza 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í también:[basic.life] / 8 nos dice que, si asigna un nuevo objeto en el almacenamiento del antiguo, no puede acceder al nuevo objeto a través de punteros al antiguo.
launder
nos permite esquivar eso.fuente
n
es unaconst
variable, el compilador es libre de asumir queu.x.n
siempre será 1." ¿Dónde en el estándar dice eso? Pregunto porque el mismo problema que usted señaló parece implicarme que es falso en primer lugar. Solo debería ser cierto bajo la regla as-if, que falla aquí. ¿Qué me estoy perdiendo?ptr
representa, entonces se rompelaunder
la condición previa, por lo que no tiene sentido hablar del resultado.memcpy
en una reinterpretación in situ en plataformas compatibles (es decir, alineación laxa) de todos modos .