2009-08-27 2 views
7

Я понимаю, что выделение памяти, сделанное в одной dll, а затем впоследствии свободно в другой, может вызвать всевозможные проблемы, особенно в отношении CRT. Подобные проблемы особенно проблематичны, когда речь идет об экспорте контейнеров STL. Мы испытывали проблем такого рода до (при написании пользовательских Adobe плагин, которые связаны с нашими библиотеками), и мы работали вокруг этих вопросов, определив собственный аллокатор, который мы используем во всех наших контейнерах, например:Распределение памяти и освобождение по границам dll

typedef std::vector < SessionFields, 
     OurAllocator <SessionFields> > 
     VectorSessionFields; 

typedef std::set < SessionFields, 
     std::less <SessionFields>, 
     OurAllocator <SessionFields> > 
     SetSessionFields; 

Это хорошо работает при передаче типов в/из нашего кода, однако мы столкнулись с проблемой в том, что теперь нам нужно вызвать функцию в SDK Adobe, которая возвращает заполненный вектор, который вызывает сбой, когда он выходит из сферы действия ,

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

Я также смотрю на создание обертки или какого-то слоя thunking, посредством чего контейнеры STL будут безопасно распределены между моим кодом и SDK (, хотя это звучит очень грязно).

В качестве альтернативы, я также рассматриваю использование GetProcessHeaps, чтобы идентифицировать кучу, используемую в SDK, и попытаться освободить ее от этой кучи вместо кучи по умолчанию.

Есть ли какие-либо советы о том, как мы можем решить эту проблему?

ответ

0

Возможно, вы попытаетесь посмотреть, существуют ли какие-либо формальные правила C++ для того, что происходит, когда исключение выбрасывается в одну DLL и попадает в другое, а затем выходит из сферы действия - похоже, очень похоже. Для исключений I думаю, что вы должны предоставить конструктор копирования специальной подписью, хотя я сейчас не уверен, что это именно так.

6

Как ни странно, в библиотеках источников Adobe имеется класс adobe::capture_allocator, который был специально написан с учетом такой безопасности в DLL. Способ, которым он работает, заключается в захвате локальных new и delete в этот момент, когда он создан, и переносит их как для жизни объекта. (См. adobe::new_delete_t для получения подробной информации о том, как он это делает, особенно в реализации here.) Деаллокация происходит с захваченной программой delete, гарантируя, что независимо от того, где вы находитесь, вы удаляете нужный delete.

Вы можете увидеть capture_allocator используется на протяжении version_1 типов в источнике библиотек Adobe, таких как adobe::any_regular_t и adobe::copy_on_write. capture_allocator должен быть совместим со всеми типами контейнеров STL.

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

+0

Это очень распространенная техника, я видел ее на С, где одна библиотека требует, чтобы ее пользователи предоставляли обратный вызов распределения/отмены выделения через какую-то точку init() библиотеки. – Justin

2

На данный момент мы работаем над dll, который предоставляет функциональность C++ через интерфейс C (для того, чтобы C# мог использовать указанную DLL).

, например: Библиотека DLL имеет STRUCT myStruct_s интерфейс предоставляет следующие функции:

interface.h

#ifndef INTERFACE_TYPES_H 
# error Please include interace_types.h 
#endif 
    myStruct_s * CreateTheStruct() { return new myStruct_s(); } 
    void DestroyTheStruct(myStruct_s * the_struct) { delete the_struct; } 
    void DoSomethingToTheStruct(myStruct_s * the_struct); 

interface_types.h

#define INTERFACE_TYPES_H 
struct myStruct_s; // fwd declaration 
#endif 

интерфейс .cpp

#if defined(__CPPPLUS) || defined(__cplusplus) || defined (__CPLUSPLUS) 
#include<TheRealFileContainingTheRealMyStruct_s.h> 
// handle the .h's functions here 
#endif 

comeOutsideCppFile.cpp

#include "interface_types.h" 
#include "interface.h" 

void main() 
{ 
    myStuct_s * x = CreateTheStruct; 
    DoSomethingToTheStruct(x); 
    DestroyTheStruct(x); 
} 

выше грубая схема того, как работает наш материал, в основном: Независимо от того длл выставляет потребности быть: Создано, обрабатывались, разрушаемый dll- сторона

Этот код не является точным на 100% !!!

Также имейте в виду, что если вы используете чистую C++ dll, вам, вероятно, нужен тот же компилятор с теми же настройками, что и для построения dll.

+1

@Maciek: interface.h должен содержать NON-встроенные функции. Выполняя функции inline, они будут скомпилированы в блоке компиляции comeOutsideCppFile.cpp, что разрушает концепцию. – shojtsy

Смежные вопросы