Дескриптор узла против std::unique_ptr

Читая документацию по интерфейсу дескриптора узла и изучая некоторые реализации стандартной библиотеки, я заметил, что многие функции типа дескриптора узла можно просто эмулировать с помощью специализации умного указателя std::unique_ptr. На самом деле функциональность типа дескриптора узла очень похожа на функциональность умного указателя std::unique_ptr. Он имеет только интерфейс, более совместимый с функциями ассоциативного контейнера, такими как псевдонимы key_type и mapped_type и функции для получения ссылки на базовое значение или значение ключа/сопоставления.

Итак, есть ли какие-либо другие преимущества, поэтому стандарт ввел тип дескриптора узла по сравнению с простой специализацией std::unique_ptr как node_type?

Можете ли вы предоставить ссылку на «документацию дескриптора узла»?

Peter Hull 31.05.2023 12:23

@PeterHull Я бы предположил, что стандартный дескриптор узла ...

Aconcagua 31.05.2023 12:25

«простая специализация std::unique_ptr» не будет соответствовать спецификации. Это бы испортило трейты и разрешение перегрузок.

Caleth 31.05.2023 14:07
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
3
83
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

С чисто философской точки зрения тот факт, что тип имеет аналогичный интерфейс с другим типом, не означает, что этот тип является избыточным и его следует заменить более общим.

В данном конкретном случае типы просто не эквивалентны. Одна из основных целей node_handle заключается в том, что вы не узнаете фактический тип узла, используемого контейнером. Даже в качестве псевдонима непрозрачного типа; node_type — это специализация node_handle, а не внутреннее имя узла.

Кроме того, учтите, что unique_ptr по своей природе является оберткой для указателя на что-то. Есть указатель, который в какой-то момент не принадлежал, тогда он принадлежит unique_ptr. Следовательно, release — разумная функция: она отказывается от указателя, не уничтожая его.

Это не разумная функция для node_handle. Вы не создавали этот узел, и поэтому вы не способны его уничтожить. Этот узел принадлежит системе, которая намеренно непрозрачна для пользователя. Любой указатель, хранящийся в нем, указывает на структуры данных, определенные реализацией, и их может быть более одной.

Но это игнорирует ключевую особенность node_handle, причину, по которой он вообще существует. Смысл node_handle в том, что вы можете извлечь элемент из такого контейнера, изменить его ключ (и, таким образом, повлиять на то, куда он будет помещен в контейнере), а затем повторно вставить его без выделения памяти. Чтобы сделать это с помощью unique_ptr<T>, потребуется, чтобы T был каким-то типом, который пользователь понимает и с которым может общаться (и, следовательно, используется для изменения ключа). Итак, что такое T?

Это не может быть value_type для контейнера, так как это делает тип ключа const и, следовательно, не поддающимся изменению. Так что это должен быть какой-то новый тип, который дает вам интерфейс для изменения значения ключа. Так как в любом случае это должен быть какой-то новый тип ... вы можете просто сделать node_handle этот тип и избавить себя от кучи боли.

Кроме того, необходимо учитывать поведение распределителя. Во-первых, node_handle также хранит копию распределителя контейнера. Чего unique_ptr не может сделать.

Во-вторых, аллокаторы с отслеживанием состояния могут иметь особое поведение при перемещении-назначении из одного контейнера в другой. В частности, вам может понадобиться переместить распределитель, когда вы это сделаете. Но для многих распределителей вы не можете. Следовательно, node_handle необходимо воспроизвести это поведение. unique_ptr тоже нельзя.

Теперь вы можете достичь всего этого, создав специализацию unique_ptr с другим интерфейсом, соответствующим вышеизложенному, за счет использования скрытых (контейнерных) имен типов в качестве параметров шаблона. Но... зачем заморачиваться? Это другой интерфейс с другим, специализированным назначением.

Так что дайте ему уже собственное имя типа. С++ не исчерпывает имена.

Хороший ответ! Однако абзац «это не может быть value_type для контейнера, так как это делает тип ключа константным и, следовательно, немодифицируемым» неверен, потому что ни std::set, ни std::map не определяют value_type как константу.

LoS 31.05.2023 17:26

@LoS: я не говорил, что они определяют value_type как const. Я сказал "тип ключа". В случае mapvalue_type является pair<const key_type, mapped_type>. А итераторы set не предлагают механизма для изменения его value_type.

Nicol Bolas 31.05.2023 17:29

Другие вопросы по теме