Используя shared_ptr в dll-интерфейсах

Если Вы производите как не-Unicode (который Вы, по-видимому, делаете), необходимо просмотреть текстовый файл, Вы создаете использование того же кодирования использования Консоли. Вот почему это выглядит корректным в консоли. В некоторых текстовых редакторах можно выбрать кодирование (или "кодовая страница") при открытии файла. (Как произвести как Unicode, который я не знаю. cmd/U не делает то, что говорит документация.)

Консольное кодирование зависит от Вашей установки Windows. Для меня это - "западноевропеец (DOS)" (или просто "MS-DOS") в Microsoft Word.

23
задан Alexey Malistov 22 October 2009 в 07:56
поделиться

4 ответа

Ответ на ваш первый вопрос: Вызывается виртуальный деструктор в вашей dll - информация о его местонахождении встроена в ваш объект (в vtable). В случае освобождения памяти это зависит от того, насколько дисциплинированы пользователи вашего IBase . Если они знают, что им нужно вызвать Release () и считают, что исключение может обойти поток управления в неожиданном направлении, будет использовано правильное направление.

Но если CreateInterface () ] возвращает shared_ptr , он может связать правильную функцию освобождения прямо с этим интеллектуальным указателем. Ваша библиотека может выглядеть так:

Destroy(IBase* p) {
    ... // whatever is needed to delete your object in the right way    
}

boost::shared_ptr<IBase> CreateInterface() {
    IBase *p = new MyConcreteBase(...);
    ...
    return shared_ptr<IBase>(p, Destroy); // bind Destroy() to the shared_ptr
}                                         // which is called instead of a plain
                                          // delete

Таким образом, каждый пользователь вашей DLL легко предотвращается от утечки ресурсов. Им никогда не придется беспокоиться о вызове Release () или обращать внимание на исключения, неожиданно обходя их поток управления.

Чтобы ответить на ваш второй вопрос: Обратная сторона этого подхода четко указана другим answer s: Ваша аудитория должна использовать тот же компилятор, компоновщик, настройки, библиотеки, что и вы. И если их может быть довольно много, это может стать серьезным недостатком для вашей библиотеки. Вы должны выбрать: безопасность или большая аудитория

Но есть возможная лазейка: Используйте shared_ptr в своем приложении, т.е.

{
    shared_ptr<IBase> p(CreateInterface(), DestroyFromLibrary);
    ...
    func();
    ...
}

Таким образом, конкретный объект реализации не передается через Граница DLL. Тем не менее ваш указатель надежно спрятан за shared_ptr , который '

19
ответ дан 29 November 2019 в 02:36
поделиться

Я бы не советовал использовать shared_ptr в интерфейсе. Даже использование C ++ вообще в интерфейсе DLL (в отличие от подпрограмм, использующих только «extern C») проблематично, потому что изменение имен не позволит вам использовать DLL с другим компилятором. Использование shared_ptr особенно проблематично, поскольку, как вы уже определили, нет гарантии, что клиент DLL будет использовать ту же реализацию shared_ptr , что и вызывающий. (Это потому, что shared_ptr является классом шаблона, а его реализация полностью содержится в файле заголовка.)

Чтобы ответить на ваши конкретные вопросы:

  1. Я не совсем понимаю, о чем вы здесь спрашиваете. ... я m предполагая, что ваша DLL будет содержать реализации классов, производных от IBase . Код их деструкторов (а также остальной код) в обоих случаях будет содержаться в DLL. Однако, если клиент инициирует уничтожение объекта (вызывая delete в первом случае или позволяя последнему экземпляру shared_ptr выйти за пределы области действия во втором случае), тогда деструктор будет вызываться из клиентского кода.

  2. Изменение имени обычно предотвращает использование вашей DLL с другим компилятором ... но реализация shared_ptr может изменить даже в новой версии того же компилятора, и это может вызвать у вас проблемы. Я бы не стал использовать второй вариант.

8
ответ дан 29 November 2019 в 02:36
поделиться
  1. Использование shared_ptr гарантирует, что функция освобождения ресурсов будет вызываться в DLL.
  2. Посмотрите ответы на этот вопрос .

Выходом из этой проблемы является создание чистого интерфейса C и тонкой полностью встроенной оболочки C ++ вокруг него.

2
ответ дан 29 November 2019 в 02:36
поделиться

По вашему первому вопросу: я делаю обоснованное предположение и не говорю из опыта, но мне кажется, что во втором случае освобождение памяти будет вызываться «в .exe». Когда вы вызываете удалить объект, происходят две вещи: во-первых, вызываются деструкторы, а во-вторых, освобождается память для объекта. Первая часть, вызов деструктора, определенно будет работать так, как вы ожидаете, вызывая правильные деструкторы в вашей dll. Однако, поскольку shared_ptr является шаблоном класса, его деструктор создается в вашем .exe, и поэтому он будет вызывать оператор delete () в вашем exe, а не в .dll. Если они были связаны с разными версиями среды выполнения (или даже статически связаны с одной и той же версией среды выполнения), это должно привести к ужасному неопределенному поведению (это та часть, в которой я не совсем уверен, но это кажется логичным) . Есть простой способ проверить, правда ли то, что я сказал - переопределить глобальный оператор delete в вашем exe, но не в вашей dll, поставить в нем точку останова и посмотреть, что вызывается во втором случае (я бы сам делаю это, но у меня, к сожалению, столько времени, чтобы расслабиться).

Обратите внимание, что те же ошибки существуют и для первого случая (вы, кажется, это понимаете, но на всякий случай). Если вы сделаете это в exe:

IBase *p = CreateInterface();
delete p;

, то вы попали в одну и ту же ловушку - вызов оператора new в dll и вызов оператора delete в exe. Вы'

1
ответ дан 29 November 2019 в 02:36
поделиться
Другие вопросы по тегам:

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