Qual é o objetivo do std :: lavagem?

242

P0137 apresenta o modelo de função std::laundere faz muitas e muitas alterações no padrão nas seções relativas a uniões, vida útil e ponteiros.

Qual é o problema que este artigo está resolvendo? Quais são as alterações no idioma que eu tenho que estar ciente? E o que estamos laundering?

Barry
fonte
2
Você está perguntando sobre o papel em si ou sobre 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".
txtechhelp
7
link útil sobre o assunto. Também esta questão stackoverflow.com/questions/27003727/…
Paul Rooney
Agora isso foi lançado no VC2017 na versão 15.7.0
Damian
De acordo com o std, os ponteiros são tipos triviais, portanto a lavagem não faz nada. ;)
curiousguy

Respostas:

250

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 Uwith {1}.

Por nser uma constvariá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 Xser 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 nmembro como 2.

Então me diga ... o que u.x.nretornará?

A resposta óbvia será 2. Mas isso está errado, porque o compilador pode assumir que uma constvariá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 constmembro é um dos fatores desqualificantes.

Então ... como podemos falar u.x.ncorretamente?

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::laundertambé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. laundernos permite dar um passo adiante.

Nicol Bolas
fonte
34
Então, meu tl; dr está correto: "a lavagem é basicamente para punições que não são do tipo UB"?
druckermanly 8/09/16
13
Você poderia explicar por que isso é verdade? "Como né uma constvariável, o compilador é livre para assumir que u.x.nsempre será 1." Onde no padrão diz isso? Eu pergunto porque o próprio problema que você apontou parece implicar para mim que é falso em primeiro lugar. Só deve ser verdade sob a regra como se, que falha aqui. o que estou perdendo?
user541686
10
@Mehrdad [basic.life] / 8: " Se um [...] novo objeto for criado no local de armazenamento em que o objeto original ocupava, [...] o nome do objeto original fará referência automaticamente ao novo objeto. se: [...] o tipo [...] não contém nenhum membro de dados não estático, cujo tipo é qualificado como const ou um tipo de referência "
ecatmur
14
@ Barry Very; se não houver objetos do tipo T localizados no endereço ptr, então você quebrará laundera pré-condição, portanto não faz sentido falar sobre o resultado.
TC
17
@NicolBolas Só se pode esperar que o supercat faça tanto lobby dos comitês quanto as que exigem interminavelmente respostas de outros usuários de idiomas de terceiros no SO. Além disso, um bom compilador de otimização otimizará sua solução correta memcpypara uma reinterpretação no local em plataformas suportadas (isto é, alinhamento laxista) de qualquer maneira .
underscore_d