Доступно ли надлежащее «владение пакетом» для «дескрипторов»?

дескрипторы имеют правильную семантику, отличную от указателей. Для меня такой пример (извлечен из Правило нуля):

class module {
public:
    explicit module(std::wstring const& name)
    : handle { ::LoadLibrary(name.c_str()), &::FreeLibrary } {}

    // other module related functions go here

private:
    using module_handle = std::unique_ptr<void, decltype(&::FreeLibrary)>;

    module_handle handle;
};

использование unique_ptr в качестве «владения в пакете» для дескрипторов — плохой пример. Во-первых, он использует внутреннее знание о том, что дескриптор является типом указателя, и использует это, чтобы сделать unique_ptr базовым типом, на котором строится "непрозрачный" тип дескриптора.

Дескрипторы могут быть любого типа, они могут быть указателями, они могут быть индексами или кто знает. Самое главное, что у вас есть под рукой (например, из большинства C API), это дескриптор и его функция освобождения ресурсов.

Существует ли правильное "владение пакетом", которое работает в семантике дескрипторов? Я имею в виду, уже общедоступны для использования?

Для меня unique_ptr эт. др. не работает, я должен делать ненужные предположения о типе дескриптора , когда я хочу просто получить «право собственности на пакет» через непрозрачный тип дескриптора и его освобождение. функция, исключительно.

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

Я процитирую здесь чувства другого пользователя SO в другом вопросе ответ:

Создайте специальный класс «умного указателя», это не займет много времени. Не злоупотребляйте библиотечными занятиями. Семантика дескриптора сильно отличается от семантики указателя C++; во-первых, разыменование HANDLE не имеет смысла.

Еще одна причина для использования собственного класса интеллектуальных дескрипторов — NULL не всегда означает пустой дескриптор. Иногда это INVALID_HANDLE_VALUE, что не одно и то же.

Отказ от ответственности:

Этот вопрос переформулируется и основывается на этом:


person pepper_chico    schedule 14.02.2013    source источник
comment
Я не согласен с вашей предпосылкой. unique_ptr может быть немного неправильным — он обрабатывает ресурсы. HANDLE также обрабатывает ресурсы. Это идеальное совпадение.   -  person Konrad Rudolph    schedule 14.02.2013
comment
Я не основываю свои предположения исключительно на названии типа...   -  person pepper_chico    schedule 14.02.2013
comment
В чем именно ваша проблема? Вам не нравится имя unique_ptr?   -  person Etienne de Martel    schedule 14.02.2013
comment
@EtiennedeMartel: Ну, при строительстве также требуется T*.   -  person Lightness Races in Orbit    schedule 14.02.2013
comment
@EtiennedeMartel: чтобы использовать unique_ptr для дескриптора без указателя, вам нужен специальный модуль удаления, который определяет вложенный тип pointer, и этот тип pointer не может быть просто, скажем, int, поскольку int не соответствует требованиям NullablePointer. что unique_ptr хочет. Однако вы можете написать простую оболочку, которая адаптирует что угодно к этим требованиям указателя с нулевым значением. Если хотите, вы также можете добавить унарный operator*, который перенаправляет на *value, и operator->, чтобы вы могли использовать *up и up->foo().   -  person Xeo    schedule 14.02.2013
comment
@Xeo, кажется, это ответ, который просит Чико - ваша оболочка вместе с небольшим количеством template, обертывающим unique_ptr.   -  person Yakk - Adam Nevraumont    schedule 14.02.2013
comment
@Xeo: Если вы собираетесь столкнуться с проблемой написания этой оболочки ... почему бы просто не написать правильный объект RAII, который может содержать любое значение, и вызвать заданную функцию / функтор для этого типа, когда он будет уничтожен? Это чертовски менее бестолково, чем использование unique_ptr для вещей, не связанных с указателем. Серьезно, написание конструкторов копирования/перемещения для одного объекта вряд ли является обременительным бременем.   -  person Nicol Bolas    schedule 15.02.2013
comment
В каком-то смысле этот вопрос, вероятно, должен был быть закрыт, потому что спрашивать библиотеки и другие ресурсы не по теме и склонны к самоуверенным ответам.   -  person Adrian McCarthy    schedule 28.08.2020


Ответы (2)


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

Если вам нужен один конкретный тип C++ (или шаблон типа), который является дескриптором без фактического определения какой-либо конкретной семантики обработки, тогда... я не могу вам помочь. Я не думаю, что кто-то сговорчиво мог.

person Lightness Races in Orbit    schedule 14.02.2013
comment
Он менее общий и, следовательно, должен использоваться там, где он подходит. Когда кто-то начинает искать, на чем построен HANDLE (предполагается, что он непрозрачный, одна из основных характеристик ручек), и использовать эту информацию в менее общем инструменте, для меня это неприятный запах. Конечно, можно утверждать, что HANDLE является void * для моего случая, а как насчет других библиотек, основанных на дескрипторах, вы собираетесь принять это утверждение? И это предположение не является частью семантики дескриптора, HANDLE непрозрачно. - person pepper_chico; 14.02.2013
comment
@chico: другие библиотеки на основе дескрипторов имеют разные типы дескрипторов. unique_ptr — это один тип дескриптора. С какой фактической проблемой вы сталкиваетесь при написании кода? - person Lightness Races in Orbit; 14.02.2013
comment
unique_ptr это один тип дескриптора? Я не знаю, что ты имеешь в виду. HANDLE является типом дескриптора. Моя реальная проблема заключается в том, чтобы игнорировать его непрозрачность, чтобы использовать unique_ptr для управления временем жизни ресурса, на который он ссылается. Я считаю это плохой практикой и прошу известную альтернативу «владения в пакете», которая делает это правильно. Под правильным я подразумеваю не нарушение инкапсуляции. Типы дескрипторов непрозрачны, и хороший инструмент будет обрабатывать дескрипторы, наконец, целочисленные и основанные на указателях, одним и тем же синтаксическим способом. - person pepper_chico; 14.02.2013
comment
@chico: Вы продолжаете говорить, что типы дескрипторов должны быть непрозрачными, но я не вижу для этого никаких причин. unique_ptr отлично подходит для дескриптора с семантикой указателя. Конечно, у него нет семантики без указателя. Это один тип дескриптора. - person Lightness Races in Orbit; 14.02.2013
comment
Неважно, не видит ли кто-то причины считать дескрипторы непрозрачными, важно то, что они обычно считаются таковыми. Вы можете построить свой тип дескриптора как void * внутри и заранее заявить своим клиентам, что он всегда будет таким. Ваши клиенты могут безопасно использовать с ним unique_ptr<void> (посмотрите, что unique_ptr<void> на самом деле не имеет смысла, вы ничего не можете сделать из типа дескриптора, это не указатель на нетипизированный). Но это касается вашей специальной ручки. Этот процесс не подходит для ручек, вообще говоря. - person pepper_chico; 14.02.2013
comment
Это нарушает инкапсуляцию, заставляет вас спрашивать, на чем построено HANDLE (и др.), где меня всегда учили считать дескрипторы непрозрачными. - person pepper_chico; 14.02.2013
comment
Вы можете использовать unique_ptr для непрозрачных дескрипторов или даже для типов, не являющихся указателями, таких как файловые дескрипторы POSIX. - person Puppy; 16.02.2013
comment
@DeadMG А функторы могут даже сохранять состояние, но они не лямбда-выражения. - person pepper_chico; 18.02.2013
comment
@chico: лямбда-выражения C++ также на самом деле не являются лямбда-выражениями. Это анонимные функторы. - person Lightness Races in Orbit; 18.02.2013
comment
@LightnessRacesinOrbit, так как у вас также есть анонимные классы, но тем не менее никто не требует для них специального синтаксиса. Дело в том, что сейчас в языке есть специальный синтаксис для таких анонимных функторов. Их удобно иметь. И они вошли в язык. Их не сложно писать. - person pepper_chico; 18.02.2013
comment
@chico: я никогда не говорил, что их нет, или что они не были, или что они есть. - person Lightness Races in Orbit; 18.02.2013

std::experimental::unique_resource

person pepper_chico    schedule 15.02.2013
comment
Зачем заставлять клиента вручную выполнять очистку (т. е. лямбду, переданную make_scoped_resource) в местах использования? - person R. Martinho Fernandes; 16.02.2013
comment
@R.MartinhoFernandes Разве это не случай unique_ptr с deleter? И если использовать default_deleter в семантике дескриптора, имеет ли это смысл? Я предполагаю, что в большинстве случаев вы получаете более короткий синтаксис с этим, и у вас есть опция std::unique_resource, которая не заставит это сделать. Но все же, я задаюсь вопросом о хорошем решении для этого. - person pepper_chico; 16.02.2013
comment
Нет, если ваш детерминатор конструируется по умолчанию. Дело в том, что make_scoped_resource, как и ctor unique_ptr, который принимает детерминант, никогда не должен использоваться в клиентском коде. Его следует использовать только в библиотечных функциях. Что-то вроде make_gl_list, которое внутренне, возможно, использует make_scoped_resource, но не заставляет клиента заботиться об этом. - person R. Martinho Fernandes; 16.02.2013
comment
@R.MartinhoFernandes Зачем заставлять пользователя языка обертывать себя всеми ситуациями, связанными с дескрипторами при использовании устаревшего API? Библиотечной функции может потребоваться один раз вызвать устаревший API для какой-либо операции, зачем принудительно выполнять перенос в такой тривиальной ситуации? Это обычное использование для людей, взаимодействующих с C, почему бы не предоставить хорошие ресурсы для решения этой проблемы? Маленькие обёртки, приватные библиотеки обёрток аналогичной функциональности, трюки с кодом, всё это должно уйти! - person pepper_chico; 16.02.2013
comment
Что. В вашем примере кода пользователь сам должен иметь дело с устаревшим API (см. там вызов glDeleteLists?). Вот что должно уйти. - person R. Martinho Fernandes; 16.02.2013
comment
@ Р. Мартиньо Фернандес ?. конечно, я говорю о работе с устаревшим API. Что мне не нравится, так это плохие практики (unique_ptr‹void, delete›) или работа с самим языком, который мешает мне в этом. - person pepper_chico; 16.02.2013