P0137 introduces the function template std::launder and makes many, many changes to the standard in the sections concerning unions, lifetime, and pointers.
What is the problem this paper is solving? What are the changes to the language that I have to be aware of? And what are we laundering?
std::launderis aptly named, though only if you know what it's for. It performs memory laundering.Consider the example in the paper:
That statement performs aggregate initialization, initializing the first member of
Uwith{1}.Because
nis aconstvariable, the compiler is free to assume thatu.x.nshall always be 1.So what happens if we do this:
Because
Xis trivial, we need not destroy the old object before creating a new one in its place, so this is perfectly legal code. The new object will have itsnmember be 2.So tell me... what will
u.x.nreturn?The obvious answer will be 2. But that's wrong, because the compiler is allowed to assume that a truly
constvariable (not merely aconst&, but an object variable declaredconst) will never change. But we just changed it.[basic.life]/8 spells out the circumstances when it is OK to access the newly created object through variables/pointers/references to the old one. And having a
constmember is one of the disqualifying factors.So... how can we talk about
u.x.nproperly?We have to launder our memory:
Money laundering is used to prevent people from tracing where you got your money from. Memory laundering is used to prevent the compiler from tracing where you got your object from, thus forcing it to avoid any optimizations that may no longer apply.
Another of the disqualifying factors is if you change the type of the object.
std::laundercan help here too:[basic.life]/8 tells us that, if you allocate a new object in the storage of the old one, you cannot access the new object through pointers to the old.
launderallows us to side-step that.