【发布时间】:2022-01-22 18:37:56
【问题描述】:
我处于以下情况:我正在编写一个必须动态加载 C++ 库的 C++ 程序(即通过dlopen 和 Linux 中的朋友以及LoadLibrary 和 Windows 中的朋友)。这可以通过创建一个 C 接口来完成。
现在,无论是在程序中还是在库中,我都管理着一些具有一些指定模板成员和一些方法的对象:
struct MyObject {
std::vector<int> _vec;
//...
void do_something();
};
现在,如果库是静态加载的,我会编写一个库函数,例如
void some_function(MyObject& o);
但由于它是动态加载的,我需要一些其他签名。我在想以下几点:一个常见的标题,如
//interface.hpp
extern "C" {
void ob_w(void*);
}
struct MyObject {
//...
}
那么,图书馆那边
//lib.cpp
#include "interface.hpp"
void ob_w(void* ptr)
{
MyObject* p = (MyObject*)ptr;
p->do_something();
}
对于主程序
//main.cpp
#include "interface.hpp"
int main()
{
void* handle = nullptr;
void (*fptr)(void*);
handle = dlopen(...)
fptr = dlsym(...)
MyObject foo;
fptr((void*)&foo);
//...
}
环顾四周,我发现了其他类似的问题,但在所有这些问题中,库都是用 C 编写的,因此采用了不同的解决方案。这里的库和程序都是用 C++ 编写的,void 指针只是为了避免一些适配器。 我想知道我的方法是否正确(我在 linux 机器上尝试过,似乎给出了正确的结果)和 安全。如果不是,我如何在不引入任何开销(例如某些适配器)的情况下传递对象的指针?
【问题讨论】:
-
使用 C++
vector作为 DLL 的参数只是糟糕的 API 设计。您应该努力使其平台和语言独立。如果您希望使用 C++ 容器,请将它们保留在 DLL 内部。如果您不想要开销,请不要使用 C++ 标准库。 -
您可以在动态链接库的签名中使用 C++ 类型就好了。理论上你没有 ABI 稳定性,但实际上这不是问题(尤其是当你同时控制库和消费者时)。
-
@Lundin
vector只是一个例子。在我的真实代码中没有vector,而是我自己定义的另一个模板。这只是一个减少行数的例子。 -
@KonradRudolph 它违背了使用 DLL 的全部目的。如果您仍然强制执行特定语言和 ABI,为什么不静态链接它?
-
@Lundin 这些并不是使用 DLL 的唯一原因。我认为,它们甚至不是主要原因。其他原因包括制作插件架构或其他不希望使用静态链接的场景。在开发 ld.so 时,对其他语言的考虑充其量只是事后的想法。这可能在 Windows 上会有所不同,不知道。