C ++: ¿Cuándo necesito un asignador de memoria compartida para std :: vector?

Primera capa

Tengo una DLL de Win32 escrita en el Service Pack 6 de VC ++ 6. Llamemos a esta DLL como FirstLayer. No tengo acceso al código fuente de FirstLayer, pero necesito llamarlo desde el código administrado. El problema es que FirstLayer hace un uso intensivo de std :: vector y std :: string como argumentos de función y no hay manera de convertir estos tipos en una aplicación de C # directamente.

Segunda capa

La solución que se me ocurre es crear primero otra DLL Win32 escrita en el Service Pack 6 de VC ++ 6. Llamemos a esta DLL como “SecondLayer”. SecondLayer actúa como un contenedor para FirstLayer. Esta capa contiene clases de envoltorio para std :: vector, por lo que std :: vector no está expuesto en todos los parámetros de función en esta capa. Llamemos a esta clase contenedora para std :: vector como StdVectorWrapper.

Esta capa no hace uso de ninguna operación nueva o de eliminación para asignar o desasignar memoria, ya que esto es manejado por std :: vector internamente.

Third_Layer

También creé una biblioteca de clases VC ++ 2005 como un contenedor para SecondLayer. Esta envoltura hace todo el trabajo sucio de convertir el SecondLayer no administrado en código administrado. Llamemos a esta capa como “ThirdLayer”.

Al igual que en SecondLayer, esta capa no hace uso de nuevo y elimina cuando se trata de StdVectorWrapper.

Cuarto_Layer

Para colmo, creé una aplicación de consola C # 2005 para llamar a ThirdLayer. Llamemos a esta aplicación de consola C # como “FourthLayer”.

Resumen de la secuencia de llamadas

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

El problema

Noté que se está lanzando la excepción ” System.AccessViolationException: bash de leer o escribir en la memoria protegida “, que sospecho que se debe a la memoria de asignación interna std :: vector de SecondLayer, que es ilegal para el acceso de ThirdLayer.

Esto se confirma, creo, porque cuando compilo FirstLayer (simulado) y SecondLayer en VC ++ 2005, el problema desaparece por completo. Sin embargo, no es posible volver a comstackr la versión de producción de FirstLayer ya que no tengo el código fuente.

He escuchado que para deshacerme de este problema, necesito escribir un asignador de memoria compartida en C ++ para el std :: vector de SecondLayer que se encuentra en la clase StdVectorWrapper. ¿No entiendo completamente por qué necesito un asignador de memoria compartida y cómo funciona? ¿Alguna idea?

¿Hay algún código fuente disponible para esto en Internet que pueda comstackr y usar junto con mi código en SecondLayer?

Tenga en cuenta que no puedo usar la biblioteca boost para esto.

Cada archivo ejecutable o dll se vincula a una versión particular de la biblioteca de tiempo de ejecución de c, que es lo que contiene la implementación de new y delete . Si dos módulos tienen comstackdores diferentes (VC2005 vs VC6) o configuraciones de comstackción (Debug vs Release) u otras configuraciones (tiempo de ejecución multiproceso vs tiempo de ejecución no multiproceso), entonces se vincularán a diferentes tiempos de ejecución c. Eso se convierte en un problema si la memoria asignada por un tiempo de ejecución es liberada por un tiempo de ejecución diferente.

Ahora, si no me equivoco, las plantillas (como std :: vector o std :: string) pueden hacer que este problema se infiltre en un lugar en el que no sea evidente de inmediato. El problema proviene del hecho de que las plantillas se comstackn en cada módulo por separado.

Ejemplo: el módulo 1 usa un vector (asignando así memoria), luego lo pasa como un parámetro de función al módulo 2, y luego el módulo 2 manipula el vector causando la desasignación de la memoria. En este caso, la memoria se asignó utilizando el tiempo de ejecución del módulo 1 y se desasignó utilizando el tiempo de ejecución del módulo 2. Si esos tiempos de ejecución son diferentes, entonces tienes un problema.

Entonces, dado todo eso, tienes dos lugares para problemas potenciales. Uno es entre FirstLayer y SecondLayer si esos dos módulos no se han comstackdo con la misma configuración exacta . El otro es entre SecondLayer y ThirdLayer si alguna memoria está asignada en una y desasignada en la otra.

Podría escribir un par de progtwigs de prueba más para confirmar qué lugares tienen problemas.

Para probar FirstLayer-SecondLayer, copie la implementación de las funciones de SecondLayer en un progtwig VC6, escriba el código suficiente para llamar a esas funciones de una manera típica, y enlace solo con FirstLayer.

Si esa primera prueba no falla, o si no, una vez que la hayas solucionado, prueba SecondLayer-ThirdLayer: copia la implementación de ThirdLayer en un progtwig VC2005, escribe el código para hacer llamadas típicas y vincula con SecondLayer.

Creo que deberías mirar una architecture de solución diferente.

El código binario generado por el vector stl VC6 y la cadena es, creo, diferente del código generado por la versión más reciente de VC debido a las muchas actualizaciones de stl. Debido a esto, no creo que su architecture funcione, ya que las dlls tendrán dos implementaciones de std :: vector y std :: string que no son compatibles con binarios.

Mi solución sugerida es volver a VC6 y escribir un nuevo contenedor dll para FirstLayer que lo exponga a través de una API de C pura: esta capa deberá comstackrse usando VC6sp6 para garantizar que sea compatible binario con FirstLayer. Luego use PInvoke en Fourth_Layer para acceder a la DLL de contenedor VC6.

He encontrado una solución para el problema. Básicamente, la clase StdVectorWrapper que escribí no implementa copia profunda. Así que todo lo que tengo que hacer es agregar lo siguiente a la clase StdVectorWrapper para implementar una copia profunda.

  • Copia Constructor
  • Operador de Asignación
  • Deconstructor

Edición: Solución alternativa

Una solución aún mejor sería utilizar clone_ptr para todos los elementos contenidos en std :: vector, así como para std :: vector. Esto elimina la necesidad del constructor de copia, el operador de asignación y el deconstructor.