Р0137 вводит шаблон функции `СТД::отмыть и многие, многие изменения в разделы, касающиеся профсоюзов, жизни, и указатели.
В чем проблема этого документа-решения? Какие изменения в языке, что я должен быть в курсе? И что нам отмывать передоза?
СТД::отмыть-это метко назвал, но только если вы знаете, что это's для. Он выполняет отмывание памяти.
Рассмотрим пример, приведенный в статье:
struct X { const int n; };
union U { X x; float f; };
...
U u = {{ 1 }};
Это заявление выполняет агрегатной инициализации, инициализации первым членом У
с {1}
.
Потому что N
- это константный
переменная, компилятор волен считать, что `у.х.н-будет всегда быть 1.
Так что' случается, если мы делаем это:
X *p = new (&u.x) X {2};
Потому что " X " - это тривиально, мы не должны уничтожить старый объект перед созданием нового на его место, так что это абсолютно легальный код. Новый объект будет иметь свою Н
члены 2.
Так скажи мне... что у.х.Н-возвращение?
Очевидный ответ будет 2. Но, что'ы не так, потому что компилятор это позволило предположить, что по-настоящему константной переменной (не просто
как const&, но объект переменной *заявил*
как const`) ничего не меняется. Но мы просто поменяли его.
[основные.жизнь]/8 изложены обстоятельства, когда это ОК, чтобы открыть вновь созданный объект через переменные/указателей/ссылок на старый. И имея `константный член-одна из дисквалифицирующие факторы.
Так что... как мы можем говорить о `у.х.Н-правильно?
Мы должны отмывать нашей памяти:
assert(*std::launder(&u.x.n) == 2); //Will be true.
Отмывание денег используется для предотвращения людей от трассировки, где вы получили свои деньги от. Отмывание память используется для предотвращения компилятор от розыска, где у тебя объект, тем самым заставляя его, чтобы избежать каких-либо оптимизаций, которые больше не могут применяться.
Другой дисквалифицирующий факторов при изменении типа объекта. СТД::отмыть
также может помочь здесь:
aligned_storage<sizeof(int), alignof(int)>::type data;
new(&data) int;
int *p = std::launder(reinterpret_cast<int*>(&data));
[основные.жизнь]/8 говорит нам, что если вы выделить новый объект в хранилище старый, вы не можете открыть новый объект через указатели на старый. "химичить" позволяет обойти это.