C ++ смешивать новые / удалять между библиотеками?
Вопрос
Если я использую ключевое слово new
в моей библиотеке (которое построено не так, как мое основное приложение), когда я удаляю его в моем основном приложении с помощью delete
, вероятность того, что я могу получить сбой / ошибку?
Решение
Да, действительно. В частности, вы видите проблемы с кучами отладки / выпуска, отличающиеся, также, если ваша библиотека использует новое размещение, или любая другая пользовательская куча, у вас будут проблемы Тем не менее, проблема отладки / выпуска является наиболее распространенной.
Другие советы
Это зависит. Если вы говорите о статической библиотеке, то вы, вероятно, будете в порядке - код будет выполняться в том же контексте, что и основная программа, с использованием той же библиотеки времени выполнения C ++. Это означает, что new
и delete
будут использовать одну и ту же кучу.
Если вы говорите об общей библиотеке (DLL), то, вероятно, у вас ничего не получится. Код, работающий в DLL, может использовать другую библиотеку времени выполнения C ++, что означает, что компоновка кучи будет другой. Возможно, DLL использует другую кучу.
Вызов delete
(в основной программе) для указателя, выделенного DLL (или наоборот), приведет к (в лучшем случае) немедленному падению или (в худшем случае) повреждению памяти, которое приведет к найдите время, чтобы выследить.
У вас есть несколько вариантов. Во-первых, использовать «фабричный метод». шаблон для создания и удаления этих объектов:
Foo *CreateFoo();
void DeleteFoo(Foo *p);
Они не должны быть реализованы в заголовочном файле.
Кроме того, вы можете определить метод Destroy
для объекта:
class Foo
{
~Foo();
public:
virtual void Destroy();
};
... опять же, не используйте это в заголовочном файле. Вы бы реализовали это так:
void Foo::Destroy()
{
delete this;
// don't do anything that accesses this object past this point.
}
Обратите внимание, что деструктор для Foo является закрытым, поэтому вам нужно вызвать Foo :: Destroy
.
Microsoft COM делает нечто подобное, где он определяет метод Release
, который удаляет объект, когда его счетчик ссылок падает до нуля.
Да, вы будете. Простое решение - предоставить функции «Создать» и «Удалить» в вашей библиотеке, которые можно вызывать из основного приложения. Функция Create выполнит новый и возвратит указатель, который позже передается в функцию Delete для удаления.
Это проблема, которую я видел только в Windows.
Системы Unixish не заставляют общие библиотеки связываться с различными версиями одной и той же библиотеки в рамках одной и той же программы, и все загруженные символы видны глобально. Это означает, что если объект размещен в одной части кода и удален в другой, для этого используется одна и та же системная библиотека.
Я должен сказать, что эта проблема, создаваемая Windows с помощью различных DLL-библиотек времени выполнения C, действительно раздражает и неестественна для программиста на C. Посмотрите на библиотеку C; у него есть такие функции, как strdup, которые размещают строку и ожидают, что программист вызовет для нее free (). Но сделайте то же самое в своей собственной библиотеке на Windows и просто дождитесь взрыва. Вам также придется подождать, потому что это не произойдет во время разработки, а только после того, как вы отдадите скомпилированную DLL какой-то другой бедной версии.
Старая новая вещь уже упоминала об этом раньше , Он также приводит список основных решений Microsoft.
Вы совершенно правы, что там есть проблема, но в большинстве случаев есть даже более простое решение, чем предлагали другие ответы (пока что). Вы можете продолжать использовать new и свободно удалять - все, что вам нужно сделать, это перегрузить new и delete для каждого класса в вашей библиотеке, который может использоваться через границы DLL.
Лично я только что определил простой класс для обеспечения необходимой функциональности:
class NewDelete
{
public:
void *operator new (size_t size);
void operator delete (void *memory);
void *operator new (size_t size, void *ptr);
void operator delete (void *memory, void *ptr);
};
Если все эти четыре функции-члена определены в одной и той же DLL, то любой класс, производный от этого класса, автоматически является "DLL-безопасным". - new и delete могут нормально использоваться на них, не беспокоясь о границах DLL.