std::launderporte bien son nom, mais seulement si vous savez à quoi il sert. Il effectue le blanchiment de la mémoire .
Prenons l'exemple du document:
struct X { const int n; };
union U { X x; float f; };
...
U u = {{ 1 }};
Cette instruction effectue une initialisation agrégée, initialisant le premier membre de Uwith {1}.
Parce qu'il ns'agit d'une constvariable, le compilateur est libre de supposer qu'il u.x.ndoit toujours être 1.
Alors, que se passe-t-il si nous faisons cela:
X *p = new (&u.x) X {2};
Parce que Xc'est trivial, nous n'avons pas besoin de détruire l'ancien objet avant d'en créer un nouveau à sa place, c'est donc un code parfaitement légal. Le nouvel objet aura son nmembre 2.
Alors dis-moi ... qu'est-ce qui u.x.nreviendra?
La réponse évidente sera 2. Mais c'est faux, car le compilateur est autorisé à supposer qu'une constvariable vraiment (pas simplement une const&, mais une variable d'objet déclarée const ) ne changera jamais . Mais nous venons de le changer.
[basic.life] / 8 décrit les circonstances dans lesquelles il est OK d'accéder à l'objet nouvellement créé via des variables / pointeurs / références à l'ancien. Et avoir un constmembre est l'un des facteurs de disqualification.
Alors ... comment parler u.x.ncorrectement?
Nous devons blanchir notre mémoire:
assert(*std::launder(&u.x.n) == 2); //Will be true.
Le blanchiment d'argent est utilisé pour empêcher les gens de retrouver d'où vous avez tiré votre argent. Le blanchiment de la mémoire est utilisé pour empêcher le compilateur de retrouver d'où vous venez votre objet, le forçant ainsi à éviter toute optimisation qui pourrait ne plus s'appliquer.
Un autre des facteurs disqualifiants est si vous changez le type de l'objet. std::launderpeut aussi aider ici:
aligned_storage<sizeof(int), alignof(int)>::type data;
new(&data) int;
int *p = std::launder(reinterpret_cast<int*>(&data));
[basic.life] / 8 nous dit que, si vous allouez un nouvel objet dans le stockage de l'ancien, vous ne pouvez pas accéder au nouvel objet via des pointeurs vers l'ancien. laundernous permet de contourner cela.
std::launder?std::launderest utilisé pour "obtenir un pointeur vers un objet créé dans le stockage occupé par un objet existant du même type, même s'il a des membres const ou reference".