如何从 dll 正确返回 std::list

Posted

技术标签:

【中文标题】如何从 dll 正确返回 std::list【英文标题】:how to correctly return std::list from dll 【发布时间】:2015-03-01 19:40:59 【问题描述】:

该项目具有以下结构: 1. DLL - 具有核心逻辑和类层次结构 2. exe - 处理命令行并启动算法的控制台应用程序 3. Dll - 测试,就像一个单元测试套件 - 硬编码填充来自第一个 Dll 的 ojects 集合并将集合传递给 exe 控制台进行处理

所以 Dll 点 3 应该返回集合(例如 std::list),集合包含多态对象,然后应该存储指针, 我更喜欢使用 std::unique_ptr 而不是原始指针

我看到 unique_ptr 仅支持移动语义,我正在使用 emplace_back 成员填充列表。 但是从与 MSVC 类导出技术相关的 Dll 中返回 std::list> 集合存在问题

如果我理解正确: 在 dll 和 exe 项目之间共享的项目标头应该包含类似这样的内容,其中 EXP_DLL 应该为 Dll 定义而为 exe 未定义

 #ifdef EXP_STL
 #    define DECLSPECIFIER __declspec(dllexport)
 #    define EXPIMP_TEMPLATE
 #else
 #    define DECLSPECIFIER __declspec(dllimport)
 #    define EXPIMP_TEMPLATE extern
 #endif

 EXPIMP_TEMPLATE template class DECLSPECIFIER std::list<std::unique_ptr<MyBassClass>>;

 std::list<std::unique_ptr<MyBassClass>> DECLSPECIFIER make_test_array();

这个定义:

 EXPIMP_TEMPLATE template class DECLSPECIFIER std::list<std::unique_ptr<MyBassClass>>;

引发错误

C2280:std::unique_ptr>::unique_ptr(const std::unique_ptr<_ty>> &)' :试图 引用已删除的函数

我看到尝试调用 unique_ptr 的复制 ctor(当然,已删除)

您能否为我澄清这些问题:

    这个实例化模板的导出声明如何在这里调用复制ctor? 您能建议如何避免这种情况的解决方案吗?

【问题讨论】:

从 DLL 中传递动态分配内存的所有权可能有点危险。我记得微软的编译器做了一些魔法让它工作,但更一般地说,我认为自定义分配器是必要的。 您能解释一下将逻辑放在 DLL 中而不是在静态库中的原因吗? 没有道理,只是用户的要求。我必须在分离的 Dll 中填充测试结构。附言当然,这不是一个生产项目,只是一个示例 您不应从 DLL 导出 C++ API。这会导致很多问题。 【参考方案1】:

假设满足以下条件:

    解决方案中的所有项目都链接同一个运行时 DLL(/MD 选项) 类 MyBaseClass 使用 DECLSPECIFIER 属性。 类 MyBaseClass 在 make_test_array 声明之前完全定义。

您根本不能导出模板专业化。只需删除行EXPIMP_TEMPLATE template class ...。 std::list 和 std::unique_ptr 代码将被内联。 您将收到警告 C4251,请忽略它。

当您尝试导出 std::list 特化时,所有 std::list&lt;T&gt; 方法被实例化。其中一些(例如赋值运算符)要求 T 是可复制的。这就是无法编译具有 unique_ptr 的特化的原因。

【讨论】:

第 1-3 点确实已经存在。但是如果我用 unique_ptrs 删除列表的导出声明,exe 中的调用者代码:std::list<:unique_ptr>> objects = make_test_array();产生错误: unresolved external std::list>..... 当然,MyBaseClass 是在该上下文中定义的,简单地替换为 std::list 使这可行,但这不是什么我要,你看 我错了 - 带有和不带有 unique_ptr 包装器的变体都会在 exe 中使用 unresolved external 引发错误 1) 您能否指定确切的错误文本。 2) 其他导出的函数是否在exe中正常链接? 2) 否 - 没有要导出的其他函数,这个示例是我的第一次体验,我之前没有导出 stl 对象 1) (目前我从列表对象中删除了 unique_ptr 并使用原始指针) main.obj:-1: LNK2019: 未解析的外部符号 "class std::list > __cdecl make_test_array(void)" (?make_test_array@@YA?AV? $list@PEAVMyBaseClass@@V?$allocator@PEAVMyBaseClass@@@std@@@std@@XZ) 在 main 函数中引用; 此代码使用:在 exe:模板类 DECLSPECIFIER std::list; int main() std::list objects = make_test_array();这在共享标题中:EXPIMP_TEMPLATE 模板类 DECLSPECIFIER std::list; std::list DECLSPECIFIER make_test_array();

以上是关于如何从 dll 正确返回 std::list的主要内容,如果未能解决你的问题,请参考以下文章

如何从 COM DLL 返回包含多个空字符的 BSTR

std::initialize_list<T;作为返回值

如何从 C 代码正确创建 DLL 并在 C++ 项目中使用它

Python 和 ctypes:如何正确地将“指针对指针”传递给 DLL?

如何在 Java 代码中使用从 .dll 使用和返回对象的函数?

如何从 C# 中的 C++ dll 中的全局变量从函数中获取返回数组?