如何在dll界面或ABI中使用标准库(STL)类?

| 在导出包含与Visual Studio警告C4251有关的stl类的类之前,存在一些问题。这个问题还是这个问题。 我已经在UnknownRoad中阅读了出色的解释。 盲目禁用警告似乎有些危险,尽管可以选择。包装所有这些std类并导出它们并不是一个真正的选择。毕竟,它被称为标准模板库...,即,一个人希望提供与这些标准类的接口。 如何在dll接口中使用stl类?什么是常见做法?     
已邀请:
在继续阅读之前,请记住一件事:我的回答是从编写可移植代码的角度出发的,该代码可在由使用不同编译器编译的模块组成的应用程序中使用。这可以包括同一编译器的不同版本,甚至不同的补丁程序级别。   我如何在我的stl类中使用   dll接口? 答:您经常不能。 原因:STL是一个代码库,而不是像DLL这样的二进制库。它没有保证可以在任何地方使用的相同ABI。确实,STL确实代表“标准模板库”,但是除标准之外,此处的一个关键操作词是模板。 该标准定义了每个STL类需要提供的方法和数据成员,并定义了这些方法的作用。但没有更多。特别是,标准未指定编译器编写者应如何实现标准定义的功能。编译器作者可以自由地提供STL类的实现,以添加标准中未列出的成员函数和成员变量,只要标准中定义的那些成员仍然存在并按照标准进行操作即可。 也许有个例子。 “ 0”类在标准中定义为具有某些成员函数和变量。标准中的实际定义几乎为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_;
};
ѭ9是什么? 假设我上面建议的实现,在MSVC10下将为ѭ10,而在SP1下将为ѭ11。如果您在使用DLL的VC10 SP1中编写应用程序,则对象的大小将看起来与实际不同。二进制接口已更改。 有关此问题的另一种处理方法,请参阅C ++编码标准(Amazon链接)第63期。 1:“您常常不能”实际上,当您完全控制工具链和库时,可以以相当高的可靠性导出标准库组件或任何其他代码库组件(例如Boost)。 根本的问题是,对于源代码库,不同的编译器和库的不同版本之间事物的大小和定义可能不同。如果您在一个可以在所有使用代码的地方都控制这两件事的环境中工作,那么您可能不会有任何问题。例如,在一家贸易公司中,所有系统都在内部编写并且仅在内部使用,这可能是可行的。     

要回复问题请先登录注册