x64 x32 visual microsoft c++ visual-studio-2010

x32 - visual c++ 2012



Una forma de eliminar la advertencia C4251 cuando se usan clases stl en la interfaz dll (4)

Creo que tienes al menos 5 opciones posibles para resolver este problema:

  1. Aún puede mantener clases de STL / plantilla para sus campos y también usarlas como tipos de parámetros, siempre y cuando mantenga todos los campos privados (lo cual es una buena práctica de todos modos). Here hay una discusión sobre esto. Para eliminar las advertencias, simplemente puede usar las declaraciones de #pragma .

  2. Podría crear pequeñas clases de envoltorios con campos de STL privados y exponer los campos de sus tipos de clases de envoltorios al público, pero es muy probable que esto solo mueva las advertencias a otros lugares.

  3. Puede usar el lenguaje PIMPL para ocultar sus campos STL en una clase de implementación privada, que ni siquiera se exportará desde su biblioteca ni será visible fuera de ella.

  4. O puede exportar todas las especializaciones de clase de plantilla requeridas, como se sugiere en la advertencia C4251, de la manera que se describe here . En resumen, tendría que insertar las siguientes líneas de código antes de su clase HelloWorld :

    ... #include <vector> template class __declspec(dllexport) std::allocator<int>; template class __declspec(dllexport) std::vector<int>; template class __declspec(dllexport) std::string; class __declspec(dllexport) HelloWorld ...

    Por cierto, el orden de esas exportaciones parece ser importante: la plantilla de clase vectorial utiliza la plantilla de clase asignadora internamente, por lo que la creación de instancias de asignación debe exportarse antes de la creación de instancias de vectores.

  5. El uso directo de intrínsecos es probablemente tu peor opción, pero si encapsulas tus campos

    int *p_abc; int abc_len;

    en algo como la class MyFancyDataArray y los campos

    char *p_str; int str_len;

    en algo como la class MyFancyString , entonces esta sería una solución más decente (similar a la descrita en el segundo punto). Pero probablemente no sea el mejor hábito reinventar la rueda con demasiada frecuencia.

No es una buena práctica usar stl-classes en la interfaz dll como práctica común para tratar con la advertencia c4251: class ... necesita tener una explicación de la interfaz dll . Se da un ejemplo:

#include <iostream> #include <string> #include <vector> class __declspec(dllexport) HelloWorld { public: HelloWorld() { abc.resize(5); for(int i=0; i<5; i++) abc[i] = i*10; str="hello the world"; } ~HelloWorld() { } std::vector<int> abc; std::string str; };

Al compilar este archivo, se pueden observar las siguientes advertencias:

warning C4251: ''HelloWorld::str'' : class ''std::basic_string<_Elem,_Traits,_Ax>'' needs to have dll-interface to be used by clients of class ''HelloWorld'' warning C4251: ''HelloWorld::abc'' : class ''std::vector<_Ty>'' needs to have dll-interface to be used by clients of class ''HelloWorld''

Entonces, la pregunta es cómo podemos implementar la misma funcionalidad sin usar el vector de clase STL y la cadena. Una implementación que podría pensar es la siguiente:

class __declspec(dllexport) HelloWorld2 { public: HelloWorld2() { abc_len = 5; p_abc = new int [abc_len]; for(int i=0; i<abc_len; i++) p_abc[i] = i*10; std::string temp_str("hello_the_world"); str_len = temp_str.size(); p_str = new char[str_len+1]; strcpy(p_str,temp_str.c_str()); } ~HelloWorld2() { delete []p_abc; delete []p_str; } int *p_abc; int abc_len; char *p_str; int str_len; };

Como puede ver, en la nueva implementación usamos int * p_abc para sustituir vector abc y char * p_str para reemplazar string str. La pregunta que tengo es si hay otros enfoques de implementación elegantes que puedan hacer lo mismo. ¡Gracias!


No estoy seguro de qué problema quieres resolver aquí. Hay dos problemas diferentes: Compatibilidad binaria entre compiladores cruzados y evitar los errores del enlazador de "símbolo indefinido". La advertencia C4251 que citó habla sobre el segundo problema. Lo que en realidad no es un problema, especialmente con clases SCL como std::string y std::vector . Ya que están implementados en el CRT, siempre que ambos lados de su aplicación utilicen el mismo CRT, todo "simplemente funcionará". La solución en ese caso es simplemente deshabilitar la advertencia.

Compatibilidad binaria entre compiladores OTOH, que es lo que se discute en la otra pregunta de que vinculó, es una bestia completamente diferente. Para que eso funcione, básicamente debe mantener todos sus archivos de encabezado públicos libres de cualquier mención de cualquier clase de SCL. Lo que significa que tienes que PIMPL todo o usar clases abstractas en todas partes (o una mezcla de ellas).


O haga lo más fácil que puede hacer, mueva __declspec a los __declspec miembros que desea exportar:

class HelloWorld { public: __declspec(dllexport) HelloWorld() { abc.resize(5); for(int i=0; i<5; i++) abc[i] = i*10; str="hello the world"; } __declspec(dllexport) ~HelloWorld() { } std::vector<int> abc; std::string str; };