我正在尝试将一些静态 C++ 库迁移到具有 C 接口的 DLL 中,因此我不需要为我们想要支持的每个版本的 Visual Studio(即 CRT)构建一个单独的库版本。不过,我确实喜欢在某些函数调用中使用 STL 对象的便利性。我想出了一些似乎可行的方法,但想知道是否可能有一些我没有想到的隐藏的东西。
这是我在保持 Visual Studio 独立性的同时获得函数的 STL 版本的方法。
原库函数:
//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 的一个版本试图从不同版本释放内存。
它似乎按我的意图执行:
- 该库可供使用多个版本的 Visual Studio 编译的程序使用。
- 没有内存泄漏或访问冲突
- 如果我修改代码以便在标头的 GetSomeString 函数中分配内存,则在尝试释放该内存时确实会出现内存访问错误。
- GetSomeString 函数由库编译并包含在 DLL 中,但它永远不会被调用,因为它是 1) 未导出和 2) 编译程序将始终选择它的版本,因为它是内联的。
有什么我遗漏的吗,或者这是为 Visual Studio 版本独立的库提供 C++ 接口的有效方法?
旁注:如果我有一个使用 a 的程序,我会遇到一些删除问题std::shared_ptr<library>
,但没有对该问题进行足够的研究,并且可能会有关于该问题的后续问题。