Ошибка std :: bad_alloc для std :: vector при использовании DLL [duplicate]

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

Одной из возможных причин ошибок компоновщика с GCC 5.2.0 является то, что новая библиотека libstdc ++ ABI теперь выбран по умолчанию.

Если вы получаете ошибки компоновщика о неопределенных ссылках на символы, которые включают типы в пространстве имен std :: __ cxx11 или теге [abi: cxx11], то это, вероятно, указывает на то, что вы пытаетесь связать файлы объектов, которые были скомпилированы с различными значениями для макроса _GLIBCXX_USE_CXX11_ABI. Это обычно происходит при подключении к сторонней библиотеке, которая была скомпилирована с более старой версией GCC. Если сторонняя библиотека не может быть перестроена с новым ABI, вам нужно будет перекомпилировать свой код со старым ABI.

. Если вы вдруг получите ошибки компоновщика при переключении на GCC после 5.1.0 это было бы замечательно.

56
задан John Dibling 3 September 2013 в 17:34
поделиться

1 ответ

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

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

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

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

Стандарт определяет методы и члены данных, которые должен предоставлять каждый класс STL, и определяет, что эти методы должны делать; но не более того. В частности, в стандарте не указывается, как разработчики компилятора должны реализовать стандартную функциональность. Авторы компилятора могут предоставить реализацию STL-класса, который добавляет функции-члены и переменные-члены, не перечисленные в Стандарте, до тех пор, пока те члены, которые определены в Стандарте, все еще существуют и выполняют то, что говорит Стандарт.

Может быть, пример в порядке. Класс basic_string определен в стандарте как имеющий определенные функции-члены & amp; переменные. Фактическое определение составляет почти 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 с пакетом обновления 1 может выглядеть так:

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

Я не говорю, что они do выглядят так, я могу сказать. Суть в том, что фактическая реализация зависит от платформы, и вы действительно не знаете, что она будет где-то еще.

Теперь скажем, что вы используете MSVC10 для записи DLL, которая экспортирует этот класс:

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

Что такое sizeof(MyGizmo)?

Предполагая, что мои предложенные реализации выше, в MSVC10 это будет sizeof(char*), но под SP1 это будет sizeof(vector<char>). Если вы пишете приложение в VC10 SP1, которое использует DLL, размер объекта будет выглядеть иначе, чем на самом деле. Бинарный интерфейс изменен.


Для получения дополнительной информации об этом см. Стандарты кодирования C ++ (ссылка Amazon ) № 63.


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

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

84
ответ дан John Dibling 26 August 2018 в 09:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: