Вопрос по windows, dll, memory, c++ – Смешение менеджера памяти DLL

2

Я написал приложение, которое позволяет людям добавлять плагины для расширения функциональности. Такие плагины развертываются в виде DLL-файлов, которые фреймворк собирает во время выполнения. Каждый плагин имеет функцию фабрики, которая вызывается несколько раз в течение жизненного цикла приложения для создания объектов. До сих пор для решения проблемы владения этими объектами я использовал простой подсчет общего указателя на возвращаемые объекты, чтобы они уничтожались при удалении последней ссылки.

Однако это имеет тенденцию вызывать сбои в Windows, поскольку не исключено, что объект будет новым в DLL плагина, но позднее (из-за вызова deref () для общего указателя) будет удален в основном приложении - и AFAIK, это смешение malloc / free - нет-нет в Windows.

Мое текущее решение этой проблемы - позволить deref () не вызывать «удалить это»; непосредственно, а не «release ();» функция, которая должна быть реализована плагинами и вызывает "удалить это". Тем не менее, довольно неприятно, что каждый плагин должен реализовывать эту тривиальную функцию - до сих пор я работал над этим, предоставляя удобство, которое должны использовать авторы макро-плагинов. У кого-нибудь есть альтернативные идеи?

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

Я был бы заинтересован в любых других взглядах на этот вопрос.

UPDATE: Я только что понял, что могу переопределить оператор new и оператор delete для базового класса объектов, возвращаемых плагинами, так что новые и их удаление всегда будут вызывать вызовы функций в одном и том же модуле (так что либо все выделения и бесплатные делаются в плагине или в структуре).

Ваш Ответ

3   ответа
3

Есть два решения. Первым решением является «поделиться больше» - вы можете перемещать новые / удалять через границы DLL, если обе стороны используют одну и ту же библиотеку CRT (/ MD или / MDd в MSVC). Второе решение - «поделиться меньше» - пусть каждая DLL имеет свою собственную кучу C ++ и не разделяет новые / удаляет через границы DLL.

2

Если код DLL отвечает за распределение объектов, он также должен отвечать за их освобождение. Я думаю, что ваша проблема связана с подсчетом ссылок и удалением & quot ;. Если вы хотите пойти по этому пути, почему бы просто не реализовать объекты как объекты COM? В конце концов, это одна из главных проблем, которые COM должен был решить!

4

Оказалось, что самый простой способ убедиться, что память не выделена в одной DLL, а освобождена в другой, это: переопределениеoperator new а такжеoperator delete на базовый класс объектов, которые возвращаются из плагинов. В реализациях этих функций вызовите «alloc» и «бесплатно»; функции (которые были переданы из основного приложения при загрузке плагина). Таким образом, плагины могут продолжать использовать «новые»; и "удалить" но память фактически будет выделена и освобождена в основном приложении.

Если вы переопределите операторы new и delete базовых классов, они будут использовать вашу память, но как насчет распределения, выполненного в этих классах? если поставщик плагина добавляет строковый член, он будет размещен в dll. Но если вы удалите объект на своей стороне, строка будет разрушена и на вашей стороне, не так ли? Я голосую за предоставление глобальных функций obj * Create () и Destroy (obj *) или AddRef () и Release (). Звучит намного безопаснее для меня.
@ eran Я понимаю, что этот комментарий опоздал примерно на 3,5 года, но я не уверен, что понимаю вашу озабоченность. Если я переопределитьoperator new а такжеoperator delete на базовом классе, и эти операторы также будут использоваться, если они используются в производных классах. Смотрите, напримерideone.com/cdNZMp который показывает два вызова к обычаюnew/delete реализации, одна пара которых вызванаreturn new Derived; вDerived::f. Frerich Raabe
Ваш пример кода создает экземпляр класса, чейoperator new переопределяется, так что вы все равно покрыты. Я думаю, что моя проблема была производным классом, имеющим поле, которое использует значение по умолчаниюnew, Этот класс & apos;new не распространяется на ваше размещение. Однако теперь, когда я прочитал это снова, я думаю, что был неправ. Все управление памятью внутри класса безопасно, поскольку то, что создано базовым классом, разрушенным базовым классом, и то, что создано производным классом, разрушено производным классом.

Похожие вопросы