【问题标题】:Exporting template code = dangerous? (MSVC)导出模板代码 = 危险? (MSVC)
【发布时间】:2009-10-16 13:57:41
【问题描述】:

正如我在另一个 SO 问题中指出的那样,我遇到了 this article。当我通过 MSVC7.1 编译 boost 1.40 并弹出几个 C4251 警告时,问题出现了。

现在,读完这篇文章后,我想知道:通常不鼓励导出模板代码,例如

class DLLEXPORT_MACRO AClass
{
public:
   std::vector<int> getVecCopy() { return myVec; }
   ...
}

假设这段代码是通过 MSVC7.1 编译成 DLL 的。 虽然此代码在从其他 MSVC7.1 代码中引用时不会产生任何错误,但据说在 MSVC8 代码中引用此 DLL 会产生运行时崩溃(内存对齐问题?)。

既然这显然很糟糕......解决导出模板代码问题的“最佳实践”是什么?

【问题讨论】:

    标签: c++ dll templates linker


    【解决方案1】:

    这似乎是一个坏主意,因为 std::vector 在编译器版本之间会有所不同或可能有所不同。但是,这可能会在加载时失败,因为 std::vector 的名称修饰在编译器版本之间应该不同(这是名称修饰的基本原理的一部分)。

    除了购买支持它的编译器之外,作为开发人员,您无法真正实施这种链接时故障。另一种解决方案是将模板类型完全排除在 DLL 接口之外。将它们放入私有成员中。

    请注意,该问题并非模板独有。想象一下,std::string 是 UDT 而不是 typedef,由编译器运行时提供。它仍然可能在编译器版本之间发生变化,当然也可能在编译器供应商之间发生变化。它仍然无法在 DLL 接口中使用。

    由于这些原因,实际的解决方案是 0. 使用 C,1. 使用 COM 或 2. 选择单一编译器版本。

    【讨论】:

    • 这是一般 C++ ABI 问题的一个方面,其中臭名昭著的“脆弱基类”问题是另一个特例。从 DLL 导出模板接口只是一场等待发生的灾难。我首选的解决方案是 MSalters 的 0 的变体:与其直接从 DLL 导出 C++,不如提供一个带有 C 绑定的薄导出层,对象指针作为不透明句柄来回传递给客户端。这样客户端就不能直接使用特定于编译器的对象内部,所以它不会有这个问题。
    • 感谢您的洞察力。虽然 (1) 不会被考虑在内,但我想我可以分别接受 (0) 或 (0') - 正如 Bob 所说的那样。事实上,我想知道为什么 boost::program_options 会造成“等待发生的灾难”。
    【解决方案2】:

    很遗憾,确实没有办法导出模板代码。外部库通常只为任何模板提供源代码。有时他们让模板使用不是模板的帮助类来隐藏专有代码。但是基本上没有办法做到这一点。

    【讨论】:

      猜你喜欢
      • 2021-08-24
      • 2023-04-07
      • 1970-01-01
      • 1970-01-01
      • 2019-04-26
      • 2011-12-28
      • 2015-07-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多