Я пытаюсь перенести некоторые статические библиотеки C ++ в библиотеки DLL с интерфейсом C, поэтому мне не нужно создавать отдельную версию библиотеки для каждой версии Visual Studio (например, CRT), которую мы хотим поддерживать. Тем не менее, мне нравится удобство использования объектов STL для некоторых вызовов функций. Я придумал что-то, что, кажется, работает, но мне было интересно, могут ли быть какие-то скрытые вещи, о которых я просто не думаю.
Вот что я придумал, чтобы получить STL-версии функций, сохраняя независимость от Visual Studio.
Функция оригинальной библиотеки:
//library.h
...
std::wstring GetSomeString();
...
StringGenerator* mStrGen; //assume forward declared for pimpl implementation
//library.cpp
std::wstring library::GetSomeString()
{
return mStrGen->GetString(); //returns a wstring;
}
Во-первых, я создал частную функцию, которая будет предоставлять интерфейс C
//library.h
__declspec(dllexport) void GetSomeStringInternal(wchar_t* pSomeString);
//library.cpp
void library::GetSomeString(wchar_t*& pSomeString)
{
if(pSomeString!= nullptr) {
delete [] pSomeString; //assumes allocated by the DLL
}
std::wstring tmpString(mStrGen->GetString());
size_t stringLength(tmpString.size());
stringToReturn = new wchar_t[stringLength + 1];
wcscpy_s(pSomeString, stringLength + 1, tmpString.c_str());
}
Затем я добавил приватную функцию, которая освобождает память, выделенную DLL
//library.h
__declspec(dllexport) void FreeArray(void* arrayPtr);
//library.cpp
void library::FreeArray(void* arrayPtr)
{
if(arrayPtr) {
delete [] arrayPtr;
}
}
Наконец, я преобразовал исходную функцию C ++, возвращающую строку, в функцию, которая вызывает внутреннюю интерфейсную функцию C
//library.h
std::wstring GetSomeString()
{
std::wstring someString(L"");
wchar_t* pSomeString= NULL;
GetSomeStringInternal(pSomeString);
someString = pSomeString;
FreeArray(pSomeString);
return someString;
}
//library.cpp
//removed GetSomeString from cpp since it is defined in header
Я думаю, что, поскольку заголовок будет компилироваться каждый раз, когда он включается, приложение, которое использует другую версию CRT, скомпилирует функцию, используя свою реализацию CRT. Все данные, передаваемые в библиотеку и из нее, используют интерфейс C для сохранения совместимости, а память выделяется и освобождается библиотекой, поэтому вы не сталкиваетесь с одной версией CRT, пытаясь освободить память из другой версии.
Кажется, чтобы выполнить, как я намерен:
Есть ли что-то, чего мне не хватает, или это правильный способ предоставления интерфейса C ++ для библиотеки, которая не зависит от версии Visual Studio?
Примечание: у меня возникли проблемы с удалением, если у меня есть программа, использующая std::shared_ptr<library>
, но не исследовали эту проблему достаточно, и, вероятно, у нее будет дополнительный вопрос по этой проблеме.
Одна проблема, с которой я столкнулся, стала проблемой, если вам действительно нужно было передавать большие объекты по ссылке из соображений производительности. Вы имеете дело с проблемами двоичной совместимости, копируя все данные в совместимый формат и из него, что нормально, пока не станет проблемой производительности.
Других решений пока нет …