Можно ли сбросить ссылку на другое значение в C ++? - PullRequest
0 голосов
/ 26 апреля 2018

Я знаю, что вообще невозможно сбросить ссылку после того, как она уже инициализирована.

Однако я как-то опробую следующий код, и он работает как на clang ++, так и на g ++.

У меня такой вопрос, является ли следующий (определенный поведением) C ++?

std::string x = "x";
std::string y = "y";
std::string i = "i";
std::string j = "j";

// now references to x, y
std::pair<std::string &, std::string &> p { x, y };
p.first = "1"; //changes x
p.second = "2"; //changes y
// now references to i, j
new (&p) std::pair<std::string &, std::string &> {i, j};
p.first = "1"; //changes i
p.second = "2"; //changes j

Приведенный выше код работает на g ++ и clang ++, но хорош ли он на C ++? Спасибо.

Ответы [ 2 ]

0 голосов
/ 26 апреля 2018

Фрагмент имеет неопределенное поведение, но это не так. Концептуально, вы уничтожили старые ссылки и создали новые, вы не перепечатали ссылку, даже если вы повторно использовали память. Эта часть полностью в порядке.

Подвох заключается в том, что если повторно используемый класс содержит const или ссылочные члены, то исходное имя переменной нельзя использовать для ссылки на новый объект

new (&p) std::pair<std::string &, std::string &> {i, j};
// p does not refer to the newly constructed object
p.first = "1";  // UB
p.second = "2"; // UB

Исправление простое, в данном случае

auto p2 = new (&p) std::pair<std::string&, std::string&> {i, j};
p2->first = "1";
p2->second = "2";

Другим решением является функция C ++ 17 std::launder

new (&p) std::pair<std::string &, std::string &> {i, j};
std::launder(&p)->first = "1";
std::launder(&p)->second = "2";

Эти правила предположительно позволяют компилятору оптимизировать работу со ссылками и константными членами.

0 голосов
/ 26 апреля 2018

У меня такой вопрос, является ли следующее (определенное поведение) C ++?

Это может быть .Ключ здесь - эта пара.Вы закончили время жизни парного объекта и запустили время жизни другого парного объекта в том же хранилище (размещение нового делает обе эти вещи).

Но вы должны знать, что вы не ссылаетесь ни на какие ссылки.Вы убиваете объект, который содержит ссылки, и создаете новый объект в том же месте.Концептуально у вас было две «старые» ссылки, а теперь две «новые».

Ваш код может быть в порядке, потому что пара представляет собой простую структуру, которая содержит пару ссылок, и она будет действительной, еслиПара держала любые тривиально разрушаемые типы.Однако, если d'tor любого элемента пары не тривиален, у вас будет неопределенное поведение.Поскольку деструкторы не будут выполняться как часть нового размещения.

Проблема как Passer По отмеченному , вы не можете использовать p для ссылки на «новый объект»,потому что он содержит ссылки.Это было бы причиной UB.

это хорошо C ++?

Это спорно.Это, конечно, не то, что можно ожидать увидеть часто.

...