P0137 представляет шаблон функции std::launder
и вносит множество изменений в стандарт в разделах, касающихся объединений, времени жизни и указателей.
Какую проблему решает эта статья? Какие изменения в языке я должен знать? И что мы думаем launder
?
std::launder
?std::launder
используется для «получения указателя на объект, созданный в хранилище, занятом существующим объектом того же типа, даже если он имеет константные или ссылочные члены».Ответы:
std::launder
удачно назван, но только если вы знаете, для чего он нужен. Он выполняет отмывание памяти .Рассмотрим пример в статье:
Этот оператор выполняет агрегатную инициализацию, инициализируя первого члена
U
с{1}
.Потому что
n
этоconst
переменная, компилятор волен считать , чтоu.x.n
должно всегда быть 1.Итак, что произойдет, если мы сделаем это:
Поскольку
X
это тривиально, нам не нужно уничтожать старый объект перед созданием нового на его месте, так что это совершенно законный код. Новый объект будет иметьn
член 2.Так скажи мне ... что
u.x.n
вернется?Очевидный ответ будет 2. Но это неправильно, потому что компилятору разрешено предполагать, что истинная
const
переменная (не просто объявленнаяconst&
, а объявленная переменная объектаconst
) никогда не изменится . Но мы просто изменили это.[basic.life] / 8 разъясняет обстоятельства, когда можно получить доступ к вновь созданному объекту через переменные / указатели / ссылки на старый. И наличие
const
члена является одним из дисквалифицирующих факторов.Итак ... как мы можем говорить
u.x.n
правильно?Мы должны отмыть нашу память:
Отмывание денег используется для предотвращения отслеживания людьми, откуда вы взяли свои деньги. Отмывание памяти используется для предотвращения отслеживания компилятором того, откуда вы получили ваш объект, что вынуждает его избегать любых оптимизаций, которые могут больше не применяться.
Еще один дисквалифицирующий фактор заключается в том, что вы меняете тип объекта.
std::launder
может помочь и здесь:[basic.life] / 8 говорит нам, что если вы выделите новый объект в хранилище старого, вы не сможете получить доступ к новому объекту через указатели на старый.
launder
позволяет нам обойти это.источник
n
этоconst
переменная, компилятор волен считать , чтоu.x.n
всегда должно быть 1.» Где в стандарте это сказано? Я спрашиваю, потому что сама проблема, на которую вы указали, может показаться, что она изначально ложна. Это должно быть верно только в соответствии с правилом «как будто», которое здесь не выполняется. Чего мне не хватает?ptr
, то вы нарушаетеlaunder
предварительное условие, поэтому нет смысла говорить о результате.memcpy
реинтерпретации на месте на поддерживаемых (т. Е. Слабое выравнивание) платформах .