为了安全起见,我已经在我的 DLL 调用中使用了旧式函数指针,如下所示:
// DLL
typedef int (__stdcall* ty)();
void test(ty t)
{
if (t)
{
int r = t();
....
}
}
Run Code Online (Sandbox Code Playgroud)
而我可以使用这个:
void test(std::function<int()> t)
{
}
Run Code Online (Sandbox Code Playgroud)
然而,众所周知,后者使用类型擦除。std::function不能是原始函数指针(因为它可能会传递一个具有捕获的 lambda,因此不能是原始指针)。
因此,在 Visual Studio 中,std::function当在调试模式下从可执行构建中使用时,在发布模式下使用带有包含崩溃的函数签名的 DLL 构建,反之亦然。即使是调试模式或发布模式,行为也不相同。有时它会崩溃,有时它会起作用。
是否有我们可以依赖使用的已定义运行时行为std::function?或者这是编译器根据我传递给它的内容专门用于编译的仅编译的东西,因此,不能直接假设运行时行为?
在汇编级别,必须知道预编译单元上的函数签名。据我所知,std::function 运行时实现没有明确定义。
所以,例如,当我编译时,然后
void test(std::function<int()> t)
Run Code Online (Sandbox Code Playgroud)
可以[]() -> int, [&]() -> int, [=]() -> int通过类型擦除采用任何参数,如, 等。但是当这是预编译的,因此只有运行时,什么是可以接受的?std::function 是如何实现的?使用类指针?有没有明确定义的方法?
我不是在寻找必然与 VS 相关的解决方案,而是寻找 的标准定义(std::function如果有的话)。
因此,在 Visual Studio 中,在发布模式下使用包含崩溃的函数签名的 DLL 构建
std::function,当在调试模式下的可执行构建中使用时,反之亦然。
这永远不会起作用,因为它改变了 ABI。
即使同时处于调试或发布模式,行为也不相同。有时它会崩溃,有时它会起作用。
如果您仔细考虑编译器标志、依赖的静态库与动态库、C 和 C++ 标准库的编译方式、异常等,这可能会起作用。这是一个复杂的主题,取决于编译器供应商的保证。
是否有我们可以依赖使用的定义的运行时行为
std::function?
一般来说,最好的选择(也是为其他语言创建绑定的最有用的选择)是避免 C++ 接口并使用具有简单类型的普通 C 接口。
也就是说,如果您想传递 C++ 类型,请将它们作为不透明类型传递,并且仅从一侧操作它们。
我不是在寻找与 VS 相关的解决方案,而是在寻找 的标准定义
std::function(如果有)。
C++ 标准不强制任何特定的 ABI,也不提供绝大多数类型的数据成员等实现细节。
这就是为什么混合不同的 STL 库也是一个问题,即使您以完全相同的方式编译所有内容。