Подтвердить что ты не робот

Как я могу использовать классы стандартной библиотеки (STL) в моем интерфейсе dll или ABI?

Перед экспортом было несколько вопросов при экспорте класса, который содержит классы stl относительно предупреждения о визуальной студии C4251: например. этот вопрос или этот вопрос. Я уже прочитал отличное объяснение в UnknownRoad.

Слепое отключение предупреждения кажется немного опасным, хотя это может быть вариант. Обертка всех этих классов std и их экспорт также не является вариантом. Это ведь называется Стандартная библиотека шаблонов... I.e., требуется предоставить интерфейс с этими стандартными классами.

Как я могу использовать stl-классы в моем dll-интерфейсе? Каковы распространенные практики?

4b9b3361

Ответ 1

Имейте в виду одну вещь, прежде чем читать дальше: Мой ответ исходит с точки зрения написания переносимого кода, который может использоваться в приложениях, составленных из модулей, скомпилированных в разных компиляторах. Это может включать разные версии или даже разные уровни патчей одного и того же компилятора.

Как я могу использовать stl-классы в моем DLL-интерфейс?

Ответ: Вы часто не можете 1.

Причина: STL - это библиотека кода, а не бинарная библиотека, такая как DLL. У него нет ни одного ABI, который гарантированно будет таким же, где бы вы его ни использовали. Действительно, STL поддерживает " Стандартную библиотеку шаблонов", но ключевое действующее слово здесь помимо Standard - Шаблон.

Стандарт определяет методы и члены данных, которые должен предоставлять каждый класс 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;) }

... В то время как MSVC 10 с SP1 может выглядеть так:

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, размер объекта будет выглядеть иначе, чем на самом деле. Изменен двоичный интерфейс.


Для другого обращения к этому, см. Стандарты кодирования С++ (Amazon ссылка) выпуск № 63.


1: " Вы часто не можете. Фактически вы можете экспортировать компоненты стандартной библиотеки или любые другие компоненты библиотеки кода (например, Boost) с достаточной надежностью когда у вас есть полный контроль над инструментами и библиотеками.

Основная проблема заключается в том, что в библиотеках исходного кода размеры и определения вещей могут быть разными между разными компиляторами и разными версиями библиотеки. Если вы работаете в среде, где вы контролируете обе эти вещи везде, где используется ваш код, у вас, вероятно, не будет проблемы. Например, в торговой фирме, где все системы написаны собственными силами и используются только внутри компании, возможно, это будет возможно.