Заметка о некоторых особенностях использования STL в DLL
От: Аноним Роман Хациев  
Дата: 26.02.02 09:57
Оценка: 371 (19) +1
Статья :
Заметка о некоторых особенностях использования STL в DLL
Автор(ы): Роман Хациев
Дата: 27.02.2002
Если вы пытались работать с экземплярами классов STL, передавая их в DLL, или получая оттуда, а потом бросили это занятие из-за непонятных ошибок, возникающих в вашей программе, то эта заметка для вас. Даже если видимых проблем в вашей программе нет, то все равно прочитайте эту заметку, чтобы знать что делать, когда они появятся :)


Авторы :
Роман Хациев

Аннотация :
Если вы пытались работать с экземплярами классов STL, передавая их в DLL, или получая оттуда, а потом бросили это занятие из-за непонятных ошибок, возникающих в вашей программе, то эта заметка для вас. Даже если видимых проблем в вашей программе нет, то все равно прочитайте эту заметку, чтобы знать что делать, когда они появятся :)
Архив с исправлениями устарел
От: FlameDancer  
Дата: 28.11.02 15:30
Оценка:
По ссылке на drinkumware последнее обновление 10 Ноября 2002.
Добавлено исправление в <vector>.
Кроме того в представленном архиве <istream> исправлен "по майкрософтовски", <string> не исправлен, <memory> не исправлен (хотя надобность в исправлении <memory> сомнительна).
Также можно добавить нижеследуюжее исправление:

In <fstream>, <f>basic_filebuf::overflow<d>, change the return statement
from:
return (fwrite(_Str->begin(), _N, 1, _File) == _N ? _C : _Tr::eof());

to:
return (fwrite(_Str->begin(), 1, _N, _File) == _N ? _C : _Tr::eof());

(C) P.J. Plauger — "главный" v Drinkumware.
Хотелось бы задать автору несколько вопросов.
От: Dima2  
Дата: 27.02.02 11:31
Оценка:
Цитата
"Следовательно, из параметров функции ничего получить нельзя. Что же происходит?
Существует два способа хранения информации о размере выделенной памяти: физический,
перед выделенным фрагментом памяти (в нашем примере по адресу p-sizeof — структуры с
информацией о блоке памяти), или же во внутренних структурах библиотеки.
Для CRT, в Visual C++, фирма Microsoft воспользовалась вторым способом."

Почему сделан вывод, что MS использует второй способ? Я бы наверное назвал его смешанным. Так если смотреть реализацию delete для DEBUG версии, то информация о выделенной памяти все-таки храниться в заголовке по адресу "p-sizeof(BlockHeader)", если быть еще точнее, то по адресу "p-0x20". Кроме размера в этом же заголовке хранится укзатели на предыдущий и следующий блоки памяти, тип блока и т.д. Т.е. на лицо связный список. А вот уже сама CRT содержит другие данные необходимые для управления этим связным списком. Так имеются глобальные переменные _pFirstBlock, _pLastBlock (указатели на заголовки блоков памяти) и другие данные. Естественно если выделить память в DLL, а попытаться удалить в приложении, при том что используются разные копии CRT, то скорее всего программа вылетит. Т.к. перед тем как удалить
блок, CRT делает кучу проверок валидности блока (заголовка блока) — есть ли данный заголовок в списке, правильный его тип и т.д. Затем пытается склеить части списка, а уже потом удаляет блок.
Выход, как уже было сказано, использовать ключ компилятора /MD. Однако тут могут возникнуть проблемы, но не то что нет нужного dll, а то что могут использоваться все равно разные dll. Если dll написана на VC4, то используется "msvcrt40.dll", а если приложение на VC5, то используется "msvcrt.dll". В некоторых локализациях Win поставляется файл "msvcrt40.dll", который переправляет все вызовы к "msvcrt.dll".
Использование STL в динамически загружаемых DLL
От: techMick  
Дата: 27.02.02 09:57
Оценка:
В своем проекте я использовал STL и в главном приложении и в динамически подключаемых DLL (LoadLibrary/GetProcAddress)
и мне приходилось передавать указатели на объекты map & list из DLL в EXE. При попытке использовать объекты созданные в DLL в основном приложенни иногда получал memory fault. После отладки оказалось что каждый экземпляр внутренних структур STL инициализировался по разному, в частности для проверки окончания списка (дерева) используется не проверка на NULL, а сравнение со static членом внутренней структуры дерева. Соответственно этот static-member по разному инициализировался в разных экземплярах STL (в EXE и в DLL). По этому использовать напрямую объект выделенный в DLL нельзя, но можно только после того как он будет скопирован в экземпляр созданный в EXE файле.
Re: Использование STL в динамически загружаемых DL
От: VoMarch  
Дата: 17.04.02 20:14
Оценка:
По поводу Проблеммы2 см. статьи в MSDN->(KB:VisualC++)->("HOWTO: Exporting STL Components Inside Outside of a Class ID: Q168958") и MSDN->(KB:VisualC++)->("PRB: Access Violation When Accessing STL Object in DLL ID: Q172396")
Re: Заметка о некоторых особенностях использования STL в DLL
От: tarkil Россия http://5209.copi.ru/
Дата: 02.11.06 06:27
Оценка:
Здравствуйте, Роман Хациев, Вы писали:

РХ>Здесь можно привести множество аргументов против инициализации и освобождения указателя в разных модулях, что это дурной стиль программирования — тот кто выделил память, тот ее и должен освобождать. Спорить не буду, но хочу напомнить, что даже инкапсуляция указателя в класс, что вряд ли является дурным стилем программирования, так же подвержена вышеописанной проблеме в силу особенностей дизайна CRT.


Кстати, boost::shared_ptr решает эту проблему. Он рядышком со счётчиком ссылок хранит и указатель на функцию, удаляющую объект. Обычно это operator delete. Хитрость в том, что запоминается указатель на operator delete именно того модуля, в котором объект создаётся!
--
wbr, Peter Taran
Re[2]: Заметка о некоторых особенностях использования STL в
От: remark Россия http://www.1024cores.net/
Дата: 02.11.06 06:34
Оценка:
Здравствуйте, tarkil, Вы писали:

T>Здравствуйте, Роман Хациев, Вы писали:


РХ>>Здесь можно привести множество аргументов против инициализации и освобождения указателя в разных модулях, что это дурной стиль программирования — тот кто выделил память, тот ее и должен освобождать. Спорить не буду, но хочу напомнить, что даже инкапсуляция указателя в класс, что вряд ли является дурным стилем программирования, так же подвержена вышеописанной проблеме в силу особенностей дизайна CRT.


T>Кстати, boost::shared_ptr решает эту проблему. Он рядышком со счётчиком ссылок хранит и указатель на функцию, удаляющую объект. Обычно это operator delete. Хитрость в том, что запоминается указатель на operator delete именно того модуля, в котором объект создаётся!


Это только вершина айсберга. Попробуй передать boost::shared_ptr<std::string> в dll и поработать там с этой строкой.
Т.ч. он практически ничего не решает. Единственное, что можно будет сделать с объектом — удалить его и не больше.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[3]: Заметка о некоторых особенностях использования STL в
От: tarkil Россия http://5209.copi.ru/
Дата: 02.11.06 06:57
Оценка:
Здравствуйте, remark, Вы писали:

R>Это только вершина айсберга. Попробуй передать boost::shared_ptr<std::string> в dll и поработать там с этой строкой.

R>Т.ч. он практически ничего не решает. Единственное, что можно будет сделать с объектом — удалить его и не больше.

Он нормально всё решает, если им управлять всей динамической памятью. Внутри std::string же не boost::shared_ptr, верно?

А STL-ным объектам можно ещё подсовывать самописные аллокаторы, которые корректно работают при пересечении границы модуля.

typedef std::basic_string<char, char_traits<char>, safeAllocator<char> > safe_string;

И юзаешь safe_string на здоровье. Вопрос реализации safeAllocator — отдельный.
--
wbr, Peter Taran
Re[4]: Заметка о некоторых особенностях использования STL в
От: remark Россия http://www.1024cores.net/
Дата: 02.11.06 07:11
Оценка:
Здравствуйте, tarkil, Вы писали:

T>Здравствуйте, remark, Вы писали:


R>>Это только вершина айсберга. Попробуй передать boost::shared_ptr<std::string> в dll и поработать там с этой строкой.

R>>Т.ч. он практически ничего не решает. Единственное, что можно будет сделать с объектом — удалить его и не больше.

T>Он нормально всё решает, если им управлять всей динамической памятью. Внутри std::string же не boost::shared_ptr, верно?


Ну так как же он решает задачу использования контейнеров стандартной библиотеки в dll?

T>А STL-ным объектам можно ещё подсовывать самописные аллокаторы, которые корректно работают при пересечении границы модуля.


T>typedef std::basic_string<char, char_traits<char>, safeAllocator<char> > safe_string;


T>И юзаешь safe_string на здоровье. Вопрос реализации safeAllocator — отдельный.


здесь
Автор: remark
Дата: 23.07.06



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[5]: Заметка о некоторых особенностях использования STL в
От: tarkil Россия http://5209.copi.ru/
Дата: 02.11.06 08:55
Оценка:
Здравствуйте, remark, Вы писали:

T>>Он нормально всё решает, если им управлять всей динамической памятью. Внутри std::string же не boost::shared_ptr, верно?

R>Ну так как же он решает задачу использования контейнеров стандартной библиотеки в dll?

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

T>>А STL-ным объектам можно ещё подсовывать самописные аллокаторы, которые корректно работают при пересечении границы модуля.

R>здесь
Автор: remark
Дата: 23.07.06


Идея виртуальной функции, как гаранта одиночности реализации мне понравилась. Но, как я понял из дискуссии, в случае агрессивной оптимизации даже вынос оных в отдельный класс-интерфейс ничего не гарантирует. Что грустно. Хоть реестр заводи.
--
wbr, Peter Taran
Re[6]: Заметка о некоторых особенностях использования STL в
От: remark Россия http://www.1024cores.net/
Дата: 02.11.06 09:02
Оценка:
Здравствуйте, tarkil, Вы писали:


T>Идея виртуальной функции, как гаранта одиночности реализации мне понравилась.


Реализации будет две. Просто будет запомнен указатель на одну из них.

T>Но, как я понял из дискуссии, в случае агрессивной оптимизации даже вынос оных в отдельный класс-интерфейс ничего не гарантирует. Что грустно. Хоть реестр заводи.


В том топике мы вроде сошлись на версии, когда в объекте аллокатора вручную запоминается указатель на функцию выделения/освобождения, а не через виртуальную функцию. По крайней мере такую версию я взял на вооружение. Как раз по причине возможной оптимизации.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[7]: Заметка о некоторых особенностях использования STL в
От: tarkil Россия http://5209.copi.ru/
Дата: 02.11.06 09:30
Оценка:
Здравствуйте, remark, Вы писали:

R>В том топике мы вроде сошлись на версии, когда в объекте аллокатора вручную запоминается указатель на функцию выделения/освобождения, а не через виртуальную функцию. По крайней мере такую версию я взял на вооружение. Как раз по причине возможной оптимизации.


Это которое Кодт предложил? Ага, дочитал (тормозит у меня сайт жутко). Хорошее решение, тоже запомнил.
--
wbr, Peter Taran
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.