Как выставить список STL за пределы библиотеки DLL?

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

  •  18-09-2019
  •  | 
  •  

Вопрос

У меня есть библиотека DLL, которой необходимо получить доступ к данным, хранящимся в контейнерах STL в главном приложении.Поскольку C ++ не имеет стандартного ABI, и я хочу поддерживать разные компиляторы, интерфейс между приложением и библиотекой DLL в основном должен оставаться обычным для старых данных.

Для векторов это относительно просто.Вы можете просто вернуть блок памяти вектора, потому что он гарантированно будет непрерывным:

// To return vector<int> data
virtual void GetVectorData(const int*& ptr, size_t& count) const
{
    if (!vec.empty())
        ptr = &(vec.front());

    count = vec.size();
}

Теперь библиотека DLL может иметь безопасный доступ только для чтения к данным вектора через этот интерфейс.Библиотека DLL также может обернуть это, чтобы скопировать содержимое в вектор и для себя.

Однако как насчет списков STL (и deques)?Есть ли другой простой способ разрешить доступ через границу DLL?Или мне придется прибегнуть к какому-то интерфейсу getFirst() / GetNext()?Возможно, мне придется сделать это для множества списков, поэтому было бы неплохо иметь такое же простое решение, как у vector.

Это было полезно?

Решение

Возможно, вы можете передать что-то вроде «дескрипторов» итераторам списка/дека?Эти типы дескрипторов будут непрозрачными и будут объявлены в заголовочном файле, который вы отправите пользователям.Внутри вам нужно будет сопоставить значения дескриптора с итераторами списка/отключения.По сути, пользователь должен написать такой код:

ListHandle lhi = GetListDataBegin();
const ListHandle lhe = GetListDataEnd();

while (lhi != lhe)
{
  int value = GetListItem(lhi);
  ...
  lhi = GetNextListItem(lhi);
}

Другие советы

Вы можете передавать объекты stl между DLL и поддерживать разные компиляторы, если будете осторожны при создании экземпляра каждого типа stl.Вам нужны интеллектуальные макросы «DLLEXPORT». Я использую следующий набор для успешной поддержки VC и gcc.

#ifdef WIN32
#ifdef MYDLLLIB_EXPORTS      // DLL export macros
#define MYDLLLIB_API __declspec(dllexport)
#define MYDLLLIB_TEMPLATE
#else
#define MYDLLLIB_API __declspec(dllimport)
#define MYDLLLIB_TEMPLATE extern
#endif
#else                       // Not windows --- probably *nix/bsd
#define MYDLLLIB_API
#ifdef MYDLLLIB_EXPORTS
#define MYDLLLIB_TEMPLATE
#else
#define MYDLLLIB_TEMPLATE extern
#endif
#endif // WIN32

При компиляции DLL определите MYDLLLIB_EXPORTS.Затем в DLL вы можете создать экземпляр каждого типа stl, который вы хотите использовать, например, списки или векторы строк.

MYDLLLIB_TEMPLATE template class MYDLLLIB_API std::vector<std::string>;
MYDLLLIB_TEMPLATE template class MYDLLLIB_API std::list<std::string>;

Потребители вашей DLL (у которых не определен MYDLLLIB_EXPORTS) увидят

extern template class __declspec(dllimport) std::vector<std::string>;

и использовать двоичный код, экспортированный из вашей DLL, вместо создания собственного экземпляра.

интерфейс между приложением и библиотекой DLL в основном должен оставаться обычными старыми данными.

Не обязательно.Вы должны быть уверены, что используется одна и та же версия компилятора.Кроме того, параметры сборки, влияющие на расположение объектов STL, точно одинаковы для библиотеки dll и приложения.

Если бы вы собирались выпустить dll на волю, вы были бы правы, если бы беспокоились о том, чтобы раскрыть STL за пределами dll-границ.Однако, если все находится под вашим контролем и чисто внутренним (или если вы можете жестко применять настройки сторонней сборки / компилятора), все должно быть в порядке.

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