Свободный указатель библиотеки C

#c #pointers #c 11

#c #указатели #c 11

Вопрос:

Я создаю простую библиотеку C MIDI, и я столкнулся с небольшой проблемой. В настоящее время я реализовал все, кроме чтения файлов. Внутри у меня есть std::vector с необработанными, динамически распределяемыми указателями (с new() ключевым словом) событий, который является абстрактным классом и поэтому не может быть создан. Теперь, когда я, наконец, приступил к чтению, возникла небольшая проблема. Мне придется самому выделять объекты, а затем и освобождать их. Однако это создает проблемы, поскольку пользователь библиотеки может включать промежуточные события или добавлять их. Это будет означать, что существуют динамические указатели, которые были созданы в другом месте в my std::vector , что делает освобождение сложным вопросом.

Чтобы сделать этот вопрос более общим, мне было интересно, что мне делать с указателями, предоставленными пользователем библиотеки. Что мне с ними делать? Я думал об одном из пунктов в списке:

  1. Освободите все указатели и обратите внимание, что указатели, переданные классу, больше не нужно освобождать (что кажется странным и нелогичным, поскольку new сопоставляется с delete в совершенно другой настройке)
  2. Поддерживайте список указателей, предоставленных пользователем, и просто пропускайте любой указатель в этом списке (вероятно, это не совсем решение, потому что весь список должен проверяться каждый раз)
  3. Создание событий доступно только с классом, поэтому пользователь не может создавать указатели с ключевым словом new, а только позволяя классу обработки выделять их.
  4. Принудительное использование общих указателей и использование их исключительно в моем коде, чтобы они автоматически освобождались, когда они выходят за пределы области видимости.
  5. Ведение списка ваших собственных указателей и только их освобождение, и пусть указатели, заданные пользователем, выходят за рамки / им придется самим их очищать.
  6. …? (что-то, о чем я, возможно, не подумал?)

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

Заранее спасибо!

Комментарии:

1. Один или несколько примеров кода помогли бы значительно улучшить этот вопрос.

2. Почему они должны быть динамически распределены? Почему вы не можете использовать интеллектуальные указатели?

3. Зачем вам нужны указатели? Просто есть вектор событий?

4. Дело в том, что Event является абстрактным классом, поскольку не должно быть экземпляра события ни с чем, это может быть только сообщение, системный или мета-событие. Однако, поскольку все они происходят из события, а событие обладает некоторой базовой функциональностью, мне это было нужно как абстрактный класс. Это означает, что, поскольку std::vector использует этот класс, он должен иметь возможность создания экземпляра, поскольку он будет скопирован. Однако это невозможно и также приведет к нарезке.

5. Подумайте об использовании boost::variant вместо наследования. События / сообщения MIDI должны иметь семантику значений. Помните: если все, что у вас есть, это молоток, все выглядит как гвоздь

Ответ №1:

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

Моим первым предложением было бы полностью избегать динамического выделения объектов. Разве вы не можете хранить a std::vector<Event> и передавать Event s по значению в свою библиотеку и из нее? Тогда пользователь может с радостью не заботиться о владельце объектов, но он может выбрать их динамическое распределение, если пожелает.

Если вам действительно нужно динамически выделять объекты, я предлагаю вам всегда заключать их в интеллектуальные указатели, чтобы управление правами собственности осуществлялось автоматически. Если, например, вы выделяете какой-либо объект от имени пользователя, стандартный интерфейс для этого выглядит примерно так:

 std::unique_ptr<Object> createObject();
  

Если, с другой стороны, в вашей библиотеке есть некоторые внутренние динамически выделяемые файлы, которыми она должна поделиться с пользователем, верните a std::shared_ptr .

Комментарии:

1. К сожалению, событие абстрактно и не может быть создано, что требует от меня обработки их как указателей, потому что это может быть практически все, что имеет событие в качестве основы.

2. Итак, я должен заставить пользователей библиотеки давать мне только интеллектуальные указатели? Это хороший стиль? Потому что для меня это просто кажется странным. Что касается согласованной политики, я бы полностью согласился, но это означало бы, что я освобождаю указатели, предоставленные пользователем, что также кажется странным. Может быть, есть другой способ единообразной обработки абстрактного класса, возможно, без использования указателей?

3. Ссылки также работают полиморфно, но, вероятно, в этом случае они были бы не очень полезны, потому что вы имеете дело с объектами с динамическим временем жизни. Итак, вы говорите, что пользователь создаст Event s и передаст их в вашу библиотеку? В этом случае это зависит от того, что вы хотите сказать пользователю. Вы говорите: «Передайте мне свой Event , и я поделюсь им с вами», или вы говорите: «Передайте мне свой Event , и я справлюсь с этим»? В первом случае возьмите shared_ptr . Во втором случае я предлагаю, чтобы идеальный интерфейс просто взял постоянную ссылку, а затем скопировал ее в библиотеку.

4. Второй случай — это именно то, что я ищу, и идеальный ответ на мой вопрос, я никогда не думал о таком решении. 🙂 Это также будет означать, что пользователю не нужно создавать все события и отслеживать их, чтобы удалить их позже, а скорее создавать одно событие, устанавливать его параметры и просто передавать их. Не должно быть необходимости заставлять пользователя отслеживать события, поскольку они могут быть получены в любом случае, если это действительно необходимо. Это решает все!