std::launder
é apropriadamente nomeado, embora apenas se você souber para que serve. Ele executa lavagem de memória .
Considere o exemplo no artigo:
struct X { const int n; };
union U { X x; float f; };
...
U u = {{ 1 }};
Essa instrução executa inicialização agregada, inicializando o primeiro membro de U
with {1}
.
Por n
ser uma const
variável, o compilador pode assumir que sempreu.x.n
deve ser 1.
Então, o que acontece se fizermos isso:
X *p = new (&u.x) X {2};
Por X
ser trivial, não precisamos destruir o objeto antigo antes de criar um novo em seu lugar, portanto esse é um código perfeitamente legal. O novo objeto terá seu n
membro como 2.
Então me diga ... o que u.x.n
retornará?
A resposta óbvia será 2. Mas isso está errado, porque o compilador pode assumir que uma const
variável verdadeiramente (não apenas uma const&
, mas uma variável de objeto declarada const
) nunca será alterada . Mas nós apenas mudamos.
[basic.life] / 8 explica as circunstâncias em que não há problema em acessar o objeto recém-criado através de variáveis / ponteiros / referências ao antigo. E ter um const
membro é um dos fatores desqualificantes.
Então ... como podemos falar u.x.n
corretamente?
Temos que lavar nossa memória:
assert(*std::launder(&u.x.n) == 2); //Will be true.
A lavagem de dinheiro é usada para impedir que as pessoas rastreiem de onde você conseguiu seu dinheiro. A lavagem de memória é usada para impedir que o compilador rastreie onde você obteve seu objeto, forçando-o a evitar otimizações que podem não se aplicar mais.
Outro dos fatores desqualificantes é se você alterar o tipo do objeto. std::launder
também pode ajudar aqui:
aligned_storage<sizeof(int), alignof(int)>::type data;
new(&data) int;
int *p = std::launder(reinterpret_cast<int*>(&data));
[basic.life] / 8 nos diz que, se você alocar um novo objeto no armazenamento do antigo, não poderá acessar o novo objeto por meio de ponteiros para o antigo. launder
nos permite dar um passo adiante.
std::launder
?std::launder
é usado para "obter um ponteiro para um objeto criado no armazenamento ocupado por um objeto existente do mesmo tipo, mesmo que possua membros const ou de referência".