C ++: Когда мне нужен распределитель общей памяти для std :: vector? - PullRequest
1 голос
/ 06 декабря 2009

First_Layer

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

Second_Layer

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

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

Third_Layer

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

Подобно SecondLayer, этот слой не использует new и delete при работе с StdVectorWrapper.

Fourth_Layer

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

Сводка последовательности вызовов

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

Проблема

Я заметил, что генерируется исключение " System.AccessViolationException: Попытка чтения или записи защищенной памяти ", что, как я подозреваю, связано с внутренней памятью std :: vector SecondLayer, которая недопустима для ThirdLayer для доступа.

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

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

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

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

Ответы [ 3 ]

0 голосов
/ 09 декабря 2009

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

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

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

0 голосов
/ 09 декабря 2009

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

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

Редактировать: Альтернативное решение

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

0 голосов
/ 06 декабря 2009

Каждый исполняемый файл или DLL ссылаются на определенную версию библиотеки времени выполнения c, которая содержит реализацию new и delete. Если два модуля имеют разные компиляторы (VC2005 против 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.

...