P0137 вводить шаблон функції std::launderта вносить багато, багато змін до стандарту в розділи, що стосуються об'єднань, часу життя та покажчиків.
Яку проблему вирішує цей документ? Які зміни в мові я повинен знати? А що ми з launderвами?
P0137 вводить шаблон функції std::launderта вносить багато, багато змін до стандарту в розділи, що стосуються об'єднань, часу життя та покажчиків.
Яку проблему вирішує цей документ? Які зміни в мові я повинен знати? А що ми з launderвами?
Відповіді:
std::launderвлучно названо, хоча тільки якщо ви знаєте, для чого це. Він виконує відмивання пам'яті .
Розглянемо приклад у статті:
struct X { const int n; };
union U { X x; float f; };
...
U u = {{ 1 }};
Ця заява виконує агрегування ініціалізації, ініціалізацію першого члена Uз {1}.
Оскільки nце constзмінна, компілятор може вільно вважати, що завждиu.x.n має бути 1.
Що ж станеться, якщо ми це зробимо:
X *p = new (&u.x) X {2};
Оскільки Xтривіально, нам не потрібно руйнувати старий об’єкт перед тим, як створити на його місці новий, тому це ідеально юридичний код. У нового об’єкта його nучасник буде 2.
Тож скажи мені ... що u.x.nповернеться?
Очевидною відповіддю буде 2. Але це неправильно, оскільки компілятору дозволено припустити, що справді constзмінна (не просто a const&, а оголошена змінна об'єкт const) ніколи не зміниться . Але ми просто змінили це.
[basic.life] / 8 викладає обставини, коли для доступу до новоствореного об’єкта є нормальним за допомогою змінних / покажчиків / посилань на старий. А наявність constчлена - один із факторів, що дискваліфікують.
Отже ... як можна u.x.nправильно говорити ?
Ми повинні відмити пам’ять:
assert(*std::launder(&u.x.n) == 2); //Will be true.
Відмивання грошей використовується для запобігання пошуку людей, звідки ви отримали свої гроші. Відмивання пам'яті використовується для запобігання компілятору відстежувати, звідки ви отримали ваш об'єкт, таким чином змушуючи його уникати будь-яких оптимізацій, які більше не застосовуються.
Ще один із факторів дискваліфікації - це якщо ви змінюєте тип об'єкта. std::launderможе допомогти і тут:
aligned_storage<sizeof(int), alignof(int)>::type data;
new(&data) int;
int *p = std::launder(reinterpret_cast<int*>(&data));
[basic.life] / 8 повідомляє нам, що якщо ви виділите новий об’єкт у сховищі старого, ви не можете отримати доступ до нового об’єкта через покажчики на старий. launderдозволяє нам у бік цього кроку.
nце constзмінна, компілятор вільний припустити, що u.x.nзавжди має бути 1." Де в стандарті це написано? Я прошу, бо сама проблема, на яку ви вказали, могла б означати, що вона в першу чергу помилкова. Це має бути істинним лише за правилом нібито, яке тут не вдається. Що я пропускаю?
ptrпредставляє, ви порушите launderпередумову, тому немає сенсу говорити про результат.
memcpyреінтерпретації на підтримуваних платформах (тобто в'яже вирівнювання) .
std::launder?std::launderвикористовується для "отримання вказівника на об'єкт, створений у сховищі, зайнятому існуючим об'єктом одного типу, навіть якщо він має const або посилання членів".