Использование результатов размещения `new` на объекте со ссылочным элементом - PullRequest
0 голосов
/ 15 октября 2018

Вопрос «Использовать ли новое для обновления ссылочного элемента?» Вопрос показывает этот пример (упрощенно):

struct Foo { int& v_; };

int a, b;
Foo f{a};

new (&f) Foo{b};

assert(&f.v_ == &a); // UB

Доступ к f через его оригинальное имя определенно является UB как объяснено ТК в связанном вопросе .Я знаю, что std::launder можно использовать для решения этой проблемы:

assert(&std::launder(&f)->v_ == &a); // OK, will fire the assert

Но как насчет использования указателя, возвращаемого путем размещения new?Т.е.

auto p = new (&f) Foo{b};    
assert(&(p->v_) == &a); // UB? OK?

В данном случае мы ссылаемся не на объект через его оригинальное имя, а через любое место размещения new.

Это неопределенное поведение или разрешено Стандартом?

1 Ответ

0 голосов
/ 16 октября 2018

Это:

auto p = new (&f) Foo{b};    
assert(&(p->v_) == &a); // UB? OK?

Четко определено.Утверждение сработает.new создает новый объект, а p указывает на этот новый объект.Это все прекрасно.Мы повторно используем хранилище f, и в [basic.life] есть много правил о том, что нормально, а что нет, о том, как можно использовать старые имена- существуют правила о том, как вы можете использовать f, предыдущие указатели на f и т. д. Вы не можете повторно использовать &f без launder.Там правила о том, как и когда вы можете вызывать деструкторы в этом случае, или как насчет повторного использования хранилища для статического хранилища или константных объектов - здесь тоже ничего не важно.

Но p - это новая вещь - она ​​просто относится к новому объекту.И p->v_ - это новый int&, который вы создали, который относится к b.Это не тот же объект, что и a, поэтому указатели сравниваются неравно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...