导出模板代码=危险?(MSVC)

msi*_*msi 1 c++ dll linker templates

正如我在另一个SO问题中所提到的,我遇到了这篇文章.当我通过MSVC7.1编译boost 1.40并弹出几个C4251警告时,问题出现了.

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

class DLLEXPORT_MACRO AClass
{
public:
   std::vector<int> getVecCopy() { return myVec; }
   ...
}
Run Code Online (Sandbox Code Playgroud)

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

因为这显然很糟糕......什么是应对导出模板代码问题的"最佳实践"?

MSa*_*ers 6

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

除了购买支持它的编译器之外,这种链接时失败是你不能真正强制执行的开发人员.另一种解决方案是将模板类型完全保留在DLL接口之外.把它们放入私人会员.

请注意,问题并非模板所独有.想象一下,这std::string是一个UDT而不是typedef,由编译器运行时提供.它仍然可以在编译器版本之间进行更改,当然也可以在编译器供 它在DLL接口中仍然无法使用.

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

  • 这是一般C++ ABI问题的一个方面,臭名昭着的"脆弱基类"问题是另一个特例.从DLL导出模板接口只是一个等待发生的灾难.我首选的解决方案是MSalters'0的变体:而不是直接从DLL导出C++,提供带有C绑定的瘦导出层,对象指针作为不透明句柄来回传递给客户端.这样客户端就不能直接使用特定于编译器的对象内部,因此它不会出现这个问题. (3认同)