c++ - 如何在我的 dll 接口(interface)或 ABI 中使用标准库 (STL) 类?

标签 c++ dll c++11 stl std

在导出包含与 Visual Studio 警告 C4251 相关的 STL 类的类之前,有几个问题:例如这个问题或这个问题。 我已经阅读了 UnknownRoad 上的精彩解释。

盲目地禁用警告似乎有点危险,尽管它可能是一种选择。包装所有这些 std 类并导出它们也不是一个真正的选择。毕竟它被称为标准模板库...即,想要为这些标准类提供一个接口(interface)。

如何在我的 dll 接口(interface)中使用 STL 类?有哪些常见做法?

最佳答案

在进一步阅读之前请记住一件事:我的回答来自编写可移植代码的角度,这些代码可用于由在不同编译器下编译的模块组成的应用程序中。这可能包括同一编译器的不同版本甚至不同的补丁级别。

How can I use stl-classes in my dll-interface?

回答:你通常不能1

原因: STL 是一个代码库,而不是像 DLL 这样的二进制库。它没有一个单一的 ABI 可以保证在您使用它的任何地方都是相同的。事实上,STL 确实代表“Standard Template Library”,但除了 Standard 之外,这里的一个关键操作词是 Template

标准定义了每个 STL 类必须提供的方法和数据成员,并定义了这些方法的用途;但没有了。特别是,标准没有指定编译器编写者应该如何实现标准定义的功能。编译器编写者可以自由地提供一个 STL 类的实现,它添加了标准中列出的成员函数和成员变量,只要这些成员在标准中定义仍然在那里,按照标准所说的去做。

也许可以举个例子。 basic_string类在标准中被定义为具有某些成员函数和变量。标准中的实际定义差不多有 4 页,但这里只是其中的一个片段:

namespace std {
  template<class charT, class traits = char_traits<charT>,
    class Allocator = allocator<charT> >
  class basic_string {
[snip]
  public:
    // 21.3.3 capacity:
    size_type size() const;
    size_type length() const;
    size_type max_size() const;
    void resize(size_type n, charT c);
    void resize(size_type n);
    size_type capacity() const;
    void reserve(size_type res_arg = 0);
    void clear();
    bool empty() const;
[snip]
};

考虑 size()length()成员函数。标准中没有任何内容指定用于保存此信息的成员变量。实际上,根本没有定义任何成员变量,甚至没有定义字符串本身。那么这是如何实现的呢?

答案是,有很多不同的方式。一些编译器可能使用 size_t成员变量来保存大小和 char*握住字符串。另一个可能使用指向保存该数据的其他数据存储的指针(这可能是引用计数实现中的情况)。事实上,同一编译器的不同版本甚至补丁级别都可能改变这些实现细节。你不能依赖他们。因此,MSVC 10 的实现可能如下所示:

namespace std {
  template<class charT, class traits = char_traits<charT>,
    class Allocator = allocator<charT> >
  class basic_string {
[snip]
char* m_pTheString;
};

size_t basic_string::size() const { return strlen(m_pTheString;) }

...而带有 SP1 的 MSVC 10 可能如下所示:

namespace std {
  template<class charT, class traits = char_traits<charT>,
    class Allocator = allocator<charT> >
  class basic_string {
[snip]
vector<char> m_TheString;
};

size_t basic_string::size() const { return m_TheString.size(); }

我不是说他们确实看起来像这样,我是说他们可能。这里的重点是实际的实现是依赖于平台的,你真的无法知道它在其他任何地方会是什么。

现在假设您使用 MSVC10 编写一个导出此类的 DLL:

class MyGizmo
{
public:
  std::string name_;
};

什么是sizeof(MyGizmo) ?

假设我在上面提出的实现,在 MSVC10 下它将是 sizeof(char*) , 但在 SP1 下它将是 sizeof(vector<char>) .如果您在 VC10 SP1 中编写使用 DLL 的应用程序,则对象的大小看起来与实际不同。二进制接口(interface)改变了。


有关此问题的另一种处理方法,请参阅 C++ 编码标准 (Amazon link ) 第 63 期。


1: "你经常做不到"你实际上可以相当可靠地导出标准库组件或任何其他代码库组件(例如 Boost)当您完全控制工具链和库时。

根本问题在于,对于源代码库,不同编译器和库的不同版本之间事物的大小和定义可能不同。如果您在使用代码的任何地方都可以控制这两个东西的环境中工作,那么您可能不会遇到问题。例如,在所有系统都在内部编写并仅在内部使用的贸易公司中,这样做是可能的。

关于c++ - 如何在我的 dll 接口(interface)或 ABI 中使用标准库 (STL) 类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5661738/

相关文章:

c++ - 有谁知道使用 GetLocaleInfoEx 的 VB(A/6) 示例?

java - 如何在具有相同回调签名的 .dll 和 .so 中使用 JNA

c++ - 指向结构体指针数组的指针

c++ - 如何将指针作为另一个方法参数传递给方法

c++ - 将 __m128i 值转换为 std::tuple

c++ - 如何在 C++ (VS2010) 中设置超时读取 USB 端口?

c++ - LNK1120 和 LNK2019 错误

c++ - 为什么这个文本没有被 ncurses 着色?

Java app通过JNI调用C++ DLL;如何最好地分配内存?

c++ - 从另一个 const std::map 初始化 const std::map 的一部分