DLL – 在 DLL 初始化时填充的静态向量,向客户端程序返回零大小

DLL – static vector which is filled up at DLL’s initialization time, returns zero size to the client program

本文关键字:DLL 客户端 程序 返回 向量 初始化 填充 静态      更新时间:2023-10-16

我在 DLL 项目中遇到以下问题:

在 DLL 端:

  • 在 DLL 中,我声明了一个静态向量,如下所示:

    static std::vector<FilterProcessor::FilterInfo*> TableOfContents;
    
  • 在静态成员的 DLL 初始化时,我正在向上述向量添加一些条目。
  • 我已经定义了一个 extern "C" 全局函数 (getTocPointer()),当它从客户端程序调用时,它会返回一个指向向量的指针。

    extern "C" __declspec(dllexport) std::vector<FilterProcessor::FilterInfo*>*  __cdecl getLibraryTOC(); 
    

在客户端的程序端:

  • DLL 库加载没有任何问题
  • 调用getProcAddress()函数时,getTocPointer()函数的地址将正确返回给客户端程序。
  • 实际上,当我在DLL端执行调试过程时,客户端程序调用上述函数,执行过程进入其中。
  • 但是,向量的大小为零,并且没有任何在初始化时添加到其中的内容。它似乎指向另一个矢量对象。

我真的不明白这里到底出了什么问题。

在初始化时向此向量添加条目的方式是正确的方法吗?

如果是,当客户端程序调用 getLibraryTOC() 函数时可能出现什么问题?

提前致谢

乔治

如果向量的静态全局定义出现在头文件中,那么是的,您确实有多个不同的向量。 将关键字static更改为extern,以使头文件声明向量而不是定义它,然后在实现文件中只添加一个定义。

然后,您可能会遇到静态初始化顺序惨败。 如果vector是在与尝试向其添加条目的代码不同的编译单元中定义的,则无法保证vector对象处于活动状态。 尝试使用构造函数尚未运行的vector是未定义的行为 - 它可能很容易表现为构造函数在之后运行并将内容设置为零长度(默认构造函数应该如此),但可能会出现许多其他问题。

您可以使用本地静态来避免 SIOF。

std::vector<FilterProcessor::FilterInfo*>& table_of_contents()
{
static std::vector<FilterProcessor::FilterInfo*> singleton;
return singleton;
}

在将访问全局的每个位置(包括填充向量的初始化逻辑)以及getLibraryTOC()导出的函数中,请改为调用访问器函数。

这一切都适用于具有多个编译单元的任何C++软件。 当你有一个DLL时,事情变得更加复杂,因为DLL和EXE是分开编译和链接的,可能具有不同的设置,不同的编译器,甚至完全不同的语言。 跨 DLL 边界共享复杂对象确实很麻烦。 如果 DLL 和 EXE 始终同时重新编译,则可以工作。 但是,如果您尝试分发 DLL 以供编写 EXE 代码的另一方使用,则强耦合将很快变得无法忍受。

更好的方法是从 DLL 边界中隐藏库对象,并仅传递基元或 OS 托管的类型。 例如:

#define DLLAPI __declspec(dllexport) __cdecl
extern "C" DLLAPI int32_t getLibraryTocCount()
{ return table_of_contents.size(); }
extern "C" DLLAPI BSTR getLibraryTocName(int index)
{ return ::SysAllocString(table_of_contents[index].name.c_str(); } // assumes std::wstring
// etc

我实现的库包含以下代码(在简要说明中):

  • 实现库目录的索引类
  • 名为 Filter01、Filter02 等的音频筛选器的集合。

索引.h

struct LIB_SPECS Library_TableOfContents
{
static  bool addTOCEntry(FilterInfo* Filter_Info);   // add an entry to the TOC
static std::vector<FilterInfo*> TableOfContents;     // TOC 
};
/*-------------------------------------------------------------------
Called from the client program to return the pointer to TOC     */
extern "C" LIB_SPECS std::vector<FlterInfo*>*  __cdecl getLibraryTOC();   

索引.cpp

/* Define / Initialize static variables */
std::vector<FilterInfo*> Library_TableOfContents::TableOfContents = {};
//=====================================================================
bool Library_TableOfContents::addTOCEntry(FilterInfo* Filter_Info)
{  
Library_TableOfContents::TableOfContents.push_back(Filter_Info);
return false;
}
//======================================================================
std::vector<FilterInfo*>* getLibraryTOC()
{
return &Library_TableOfContents::TableOfContents;
}

对于库中的每个音频过滤器:

过滤器xx.h

class LIB_SPECS Filterxx
{
public:
static struct FilterInfo
{
public:
std::string filterName;
std::string filterDescription;
// other filter info
FilterInfo();                   // FilterInfo constructor
} Filter_Info;
virtual String doSomeWork(int AvatarId);
virtual void deleteFilter() = 0;
};

过滤器xx.cpp

Filterxx::FilterInfo Filterxx::Filter_Info("Filterxx", “A filter description e.g. Low pass Filter ” );   //  
FilterInfo::FilterInfo(std::string name, std::string description)
{
Filter_Info.filterName = name;
Filter_Info.filterDescription = description;
Library_TableOfContents::addTOCEntry(&Filter_Info);
}
// other filter functions

getLibraryTOC() 函数从客户端程序调用以获取目录,以便向用户显示。 正如我所说,它确实是由客户调用的,但在调用时,目录的大小似乎为零。

相关文章: