C ++ смешивать новые / удалять между библиотеками?

StackOverflow https://stackoverflow.com/questions/443147

  •  22-07-2019
  •  | 
  •  

Вопрос

Если я использую ключевое слово 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.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top