如何在我的dll接口或ABI中使用标准库(STL)类? [英] How can I use Standard Library (STL) classes in my dll interface or ABI?

查看:161
本文介绍了如何在我的dll接口或ABI中使用标准库(STL)类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在导出包含stl类的类的视觉工作室警告C4251有几个问题:例如。这个问题或这个问题。
我已经在UnknownRoad阅读了很好的解释。



盲目禁用警告似乎有点危险,虽然它可能是一个选项。包装所有这些std类并导出这些类也不是一个选项。它总是称为标准模板库...我想要提供一个界面与这些标准类。



我如何在我的dll接口使用stl类?常见做法是什么?

解决方案

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


如何在我的
中使用stl- dll-interface?


答案:您通常不能 1



原因: STL是一个代码库,而不是像DLL这样的二进制库。它没有一个单一的ABI,保证是相同的,无论你可能使用它。事实上,STL代表标准模板库,但除了Standard之外,此处的关键操作词是模板



标准定义了每个STL类需要提供的方法和数据成员,并定义了这些方法的作用;但没有更多。特别是,该标准没有规定编译器编写器应如何实现标准定义的功能。编译器编写者可以自由地提供STL类的实现,该类添加了标准中列出的成员函数和成员变量,只要 在标准中定义的成员仍然存在,并执行标准所述。



也许一个例子是为了。 basic_string 类在标准中定义为具有某些成员函数&变量。实际的定义在标准中几乎是4页,但这里只是一个片段:

 命名空间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>)。如果在使用DLL的VC10 SP1中编写应用程序,对象的大小将看起来与实际不同。 (亚马逊链接)问题#63。






1 您通常不能实际上,您可以导出标准库组件或任何其他代码库组件



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


There have been a few questions before on exporting a class which contains stl classes in relation to visual studio warning C4251: E.g. this question or this question. I have already read the excellent explanation at UnknownRoad.

Blindly disabling the warning seems a little dangerous, though it may be an option. Wrapping all those std classes and exporting those is also not really an option. It is after all called the Standard Template Library... I.e., one wants to provide an interface with these standard classes.

How can I use stl-classes in my dll-interface? What are common practices?

解决方案

Keep in mind one thing before you read further: My answer is coming from the point of view of writing portable code that can be used in applications made up of modules compiled under different compilers. This can include different versions or even different patch levels of the same compiler.

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

Answer: You often can't1.

Reason: The STL is a code library, not a binary library like a DLL. It does not have a single ABI that is guaranteed to be the same wherever you might use it. Indeed, STL does stand for "Standard Template Library," but a key operative word here besides Standard is Template.

The Standard defines the methods and data members each STL class is required to provide, and it defines what those methods are to do; but no more. In particular, the Standard doesn't specify how compiler writers should implement the Standard-defined functionality. Compiler writers are free to provide a implementation of an STL class that adds member functions and member variables not listed in the Standard, so long as those members which are defined in the Standard are still there and do what the Standard says.

Maybe an example is in order. The basic_string class is defined in the Standard as having certain member functions & variables. The actual definition is almost 4 pages in the Standard, but here's just a snippet of it:

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]
};

Consider the size() and length() member functions. There is nothing in the Standard that specified member variables for holding this information. Indeed, there are no member variables defined at all, not even to hold the string itself. So how is this implemented?

The answer is, many different ways. Some compilers might use a size_t member variable to hold the size and a char* to hold the string. Another one might use a pointer to some other data store which holds that data (this might be the case in a reference-counted implementation). In fact, different versions or even patch levels of the same compiler may change these implementation details. You can't rely on them. So, MSVC 10's implementation might look like this:

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;) }

...Whereas MSVC 10 with SP1 might look like this:

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(); }

I'm not saying they do look like this, I'm saying they might. The point here is the actual implementation is platform-dependent, and you really have no way of knowing what it will be anywhere else.

Now say you use MSVC10 to write a DLL that exports this class:

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

What is the sizeof(MyGizmo)?

Assuming my proposed implementations above, under MSVC10 its going to be sizeof(char*), but under SP1 it will be sizeof(vector<char>). If you write an application in VC10 SP1 that uses the DLL, the size of the object will look different than it actually is. The binary interface is changed.


For another treatment of this, please see C++ Coding Standards (Amazon link) issue # 63.


1: "You often can't" You actually can export Standard Library components or any other code library components (such as Boost) with a fair amount of reliability when you have complete control over the toolchains and the libraries.

The fundamental problem is that with source code libraries the sizes and definitions of things can be different between different compilers and different versions of the library. If you are working in an environment where you control both of these things everywhere your code is used, then you probably won't have a problem. For example at a trading firm where all the systems are written in-house and used only in-house, it might be possible to do this.

这篇关于如何在我的dll接口或ABI中使用标准库(STL)类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆