Можно ли сбросить ссылку на другое значение в 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++?
это спорно. Это, конечно, не то, что можно было бы ожидать увидеть часто.