Я пишу класс шаблона, похожий на std::map. В настоящее время я работаю над реализацией функции, эквивалентной std::map::extract(). Это должно вернуть дескриптор узла со своей собственной функцией node_type::key(), которая возвращает неконстантную ссылку на ключ. Таким образом, это позволяет изменить ключ, связанный с сопоставленным объектом, и, таким образом, избежать перемещения сопоставленного объекта.
std::map показывает свое значение как std::pair<const Key,T>, но каким-то образом позволяет изменить объект Key через объект node_type. Я не понимаю, как с этим справляются реализации STL? Я склонен полагать, что они включают преобразования const_cast, но все ресурсы, которые я читал, настоятельно не рекомендуют использовать const_casts из-за опасений неопределенного поведения, особенно при последующем изменении значения.
Этот ресурс вызывает «магию реализации».
Как я могу реализовать std::map::extract(), не вызывая неопределенного поведения?
std::map, вероятно, не обрабатывает std::pair<const Key, T> внутренне, но лучше подходит для типа узла (у меня нет доказательств этого, это только мое предположение).
@Fareanor Но это означало бы, что для любого доступа к паре потребуется копия значения
Итератор @Fareanor std::map разыменовывает std::pair<const Key, T>, а это означает, что должен быть базовый pair объект, не так ли?
@BoP Тогда мой вопрос: как мне это сделать?
@gerum Вы правы, это опровергает мое предположение. В этом случае я не знаю, как это делается (но данный ответ, кажется, дает хорошее объяснение).
@chiasmos «магия реализации» создается путем разговора с ребятами, пишущими компилятор. Возможно, они могут добавить функцию __builtin_x для нужного вам x. Или пусть у вас есть #pragma magic make_this_work :-)





Как я могу реализовать
std::map::extract(), не вызывая неопределенного поведения?
Вы не можете. Стандарт определяет поведение, которое невозможно реализовать в переносимом C++.
Разработчик (C++) должен будет иметь дополнительные гарантии, определяемые реализацией, которые не должны подвергаться воздействию пользовательского кода, чтобы справиться с этим требованием. В просторечии это известно как «магия реализации».
Что вы можете сделать, так это написать предложение, представить его комитету и добиться его включения в будущий стандарт; так что есть механизм, с помощью которого это может быть достигнуто. неявные типы времени жизни, появившиеся в C++20, сделали то же самое, что и требования к std::vector::data.
Интересный. Кажется, это ответ, который я ищу, спасибо. Не могли бы вы уточнить, что вы подразумеваете под «портативным» С++ здесь? Я предполагаю, что это означает, что реализация зависит от платформы, но почему это должно быть так?
@chiasmos Когда вы начинаете с std::pair<const Key, Value> и некоторых действительных указателей и ссылок на эти объекты, превращаете их в std::pair<Key, Value>, а затем обратно в std::pair<const Key, Value>, указатели и ссылки по-прежнему должны быть действительными. Правила о времени жизни объектов не позволяют этого. Какое бы решение ни придумал реализатор, оно должно быть привязано к остальной части реализации.
Реализации могут избежать неопределенного поведения, просто определив его для конкретного варианта использования. Это "магия реализации".