Можно ли сбросить ссылку на другое значение в C++?

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

однако я как-то пробую следующий код, и он работает как на 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 ответов


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

прикол если повторно используемый класс содержит 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";

эти правила предположительно позволяет компилятору делать больше оптимизаций вокруг ссылок и членов const.


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

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

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

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

проблемы прохожий отметил, это то, что вы не можете использовать p to обратитесь к" новому объекту", поскольку он содержит ссылки. Это было бы причиной UB.

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

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