Ответ 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) с достаточной надежностью когда у вас есть полный контроль над инструментами и библиотеками.
Основная проблема заключается в том, что в библиотеках исходного кода размеры и определения вещей могут быть разными между разными компиляторами и разными версиями библиотеки. Если вы работаете в среде, где вы контролируете обе эти вещи везде, где используется ваш код, у вас, вероятно, не будет проблемы. Например, в торговой фирме, где все системы написаны собственными силами и используются только внутри компании, возможно, это будет возможно.