无论CRT版本如何,这都是在库中提供STL函数的有效方法吗

Is this a valid way to provide STL functions in a library regardless of CRT version?

本文关键字:STL 函数 方法 有效 版本 CRT 无论      更新时间:2023-10-16

我正在尝试将一些静态C++库迁移到具有C接口的DLL中,这样我就不需要为我们想要支持的每个版本的Visual Studio(即CRT)构建单独的库版本。然而,我确实喜欢在一些函数调用中使用STL对象的便利性。我想出了一些似乎有效的东西,但我想知道是否有一些隐藏的东西我只是没有想到。

以下是我在保持VisualStudio独立性的同时获得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++接口的有效方法吗?

附带说明:如果我有一个使用std::shared_ptr<library>的程序,我会遇到一些删除问题,但还没有对这个问题进行足够的研究,可能会有一个关于这个问题的后续问题。

我认为有一件事会成为一个问题,那就是如果出于性能原因,您实际上需要通过引用传递大型对象。您通过将所有数据复制到兼容格式来处理二进制兼容性问题,这在成为性能问题之前是可以的。