2009-12-06 2 views
1

First_LayerC++: Когда мне нужен распределитель разделяемой памяти для std :: vector?

У меня есть Win32 DLL, написанный на VC++ 6 пакет обновления 6. Назовём эту DLL как FirstLayer. У меня нет доступа к исходному коду FirstLayer, но мне нужно вызвать его из управляемого кода. Проблема заключается в том, что FirstLayer активно использует std :: vector и std :: string в качестве аргументов функции, и нет никакого способа маршировать эти типы в приложение C# напрямую.

Second_Layer

Решение, которое я могу думать о том, чтобы сначала создать другой Win32 DLL, написанный на VC++ 6 пакет обновления 6. Назовём эту DLL как «SecondLayer». SecondLayer действует как обертка для FirstLayer. Этот слой содержит классы-оболочки для std :: vector, поэтому std :: vector не отображается во всех параметрах функции в этом слое. Назовем этот класс-оболочку для std :: vector как StdVectorWrapper.

Этот слой не использует никаких новых или удаленных операций для выделения или освобождения памяти, так как он обрабатывается std :: vector внутренне.

Third_Layer

Я также создал библиотеку классов VC++ 2005 в качестве оболочки для SecondLayer. Эта оболочка выполняет всю грязную работу по преобразованию неуправляемого второго слоя в управляемый код. Назовем этот слой «третьим слоем».

Как и SecondLayer, этот слой не использует новые и удаляет при работе с StdVectorWrapper.

Fourth_Layer

В довершение всего, я создал # 2005 консольное приложение C для вызова ThirdLayer. Назовем это консольное приложение C# «FourthLayer».

Последовательность вызовов Резюме

FourthLayer (C# 2005) -> ThirdLayer (VC++ 2005) -> SecondLayer (VC++ 6) -> FirstLayer (VC++ 6)

Проблема

Я заметил, что «System.AccessViolationException: Попытка чтения или записи в защищенную память» исключение бросают, который я подозреваю, что из-за внутренней станд :: вектор распределения памяти SecondLayer в whic h является незаконным для доступа третьих лиц.

Это подтверждается, я думаю, потому что, когда я перекомпилирую FirstLayer (имитируемый) и SecondLayer в VC++ 2005, проблема полностью исчезает. Однако перекомпиляция производственной версии FirstLayer невозможна, так как у меня нет исходного кода.

Я слышал, что для того, чтобы избавиться от этой проблемы, мне нужно написать распределенный распределитель памяти в C++ для std :: vector SecondLayer, который находится в классе StdVectorWrapper. Я не совсем понимаю, почему мне нужен распределитель разделяемой памяти и как он работает? Есть идеи?

Есть ли какой-либо доступный исходный код для этого в Интернете, который я могу только компилировать и использовать вместе с моим кодом в SecondLayer?

Обратите внимание, что я не могу использовать библиотеку boost для этого.

+0

Забудьте мой первый ответ. Это было не правильно. –

ответ

0

Я нашел решение проблемы. В принципе, класс StdVectorWrapper, который я написал, не реализует глубокую копию. Так что все, что мне нужно сделать, это добавить в класс StdVectorWrapper следующее, чтобы реализовать глубокую копию.

  • Конструктор копирования
  • Оператор присваивания
  • Разрушитель

Edit: Альтернативное решение

Даже лучшим решением было бы использовать clone_ptr для всех элементов, содержащихся в станд :: вектор а также для самого std :: vector. Это устраняет необходимость в конструкторе копирования, операторе присваивания и деконструкторе.

0

Каждый исполняемый файл или dll ссылается на определенную версию библиотеки времени выполнения c, которая представляет собой реализацию new и delete. Если у двух модулей есть разные компиляторы (VC2005 vs VC6) или настройки сборки (Debug vs Release) или другие настройки (многопотоковая среда выполнения против многопотоковой среды выполнения), они будут ссылаться на разные сеансы c. Это становится проблемой, если память, выделенная одной средой выполнения, освобождается другой средой выполнения.

Теперь, если я не ошибаюсь, шаблоны (такие как std :: vector или std :: string) могут вызвать эту проблему, чтобы проникнуть туда, где она не сразу очевидна. Проблема возникает из-за того, что шаблоны скомпилированы в каждый модуль отдельно.

Пример: модуль 1 использует вектор (таким образом выделяя память), затем передает его как функциональный параметр в модуль 2, а затем модуль 2 манипулирует вектором, вызывающим освобождение памяти. В этом случае память была распределена с использованием времени выполнения модуля 1 и освобождена с использованием времени выполнения модуля 2. Если эти времена работы разные, тогда у вас есть проблема.

Так что при всем этом у вас есть два места для потенциальных проблем. Один находится между FirstLayer и SecondLayer, если эти два модуля не были скомпилированы с такими же настройками . Другое - между SecondLayer и ThirdLayer, если любая память выделяется в одном и освобождается в другом.

Вы можете написать еще пару тестовых программ, чтобы подтвердить, какие места (места) имеют проблемы.

Чтобы протестировать FirstLayer-SecondLayer, скопируйте реализацию функций SecondLayer в программу VC6, напишите достаточно кода, чтобы вызвать эти функции типичным образом и ссылаться только на FirstLayer.

Если этот первый тест не сработает, либо после его исправления, затем протестируйте SecondLayer-ThirdLayer: скопируйте реализацию ThirdLayer в программу VC2005, напишите код, чтобы сделать типичные вызовы, и ссылку на SecondLayer.

0

Я думаю, вам стоит взглянуть на другую архитектуру решения.

Двоичный код, сгенерированный вектором и строкой VC6 stl, по-моему, отличается от кода, созданного более поздней версией VC из-за многих обновлений stl. Из-за этого я не думаю, что ваша архитектура будет работать, поскольку библиотеки dll будут иметь две реализации std :: vector и std :: string, которые не совместимы с бинарными.

Мое предлагаемое решение - вернуться к VC6 и написать новую оболочку-оболочку для FirstLayer, которая предоставляет ее через чистый API C - этот уровень необходимо будет скомпилировать с помощью VC6sp6, чтобы обеспечить его совместимость с FirstLayer. Затем используйте PInvoke в Fourth_Layer для доступа к DLL-оболочке VC6.

Смежные вопросы