2012-01-23 10 views
8

OK, así que he leído varias preguntas y artículos sobre este tema, y ​​siento que entiendo los conceptos básicos, pero sigo teniendo problemas .Al exportar la plantilla STL std :: basic_string desde DLL, recibo un error LNK2005

Tengo una DLL que exporta una clase que tiene std :: string como miembro. Mi programa principal contiene clases que también tienen cadenas y usa la DLL.

Si puedo compilar el archivo DLL en VS2010, consigo las siguientes advertencias:

warning C4251: 'MyClass::data' : class 'std::basic_string<_Elem,_Traits,_Ax>' needs to have dll-interface to be used by clients of class 'MyClass' 

Cuando puedo compilar el EXE, consigo las mismas advertencias, pero no hay errores, y el programa compila y ejecuta. En realidad, es un proyecto grande, así que recibo 40 advertencias, y no estoy muy interesado en eso. (Como un lado-observación, estas advertencias no están presentes cuando se compila con VS2008)

Así, leí acerca de que la alerta, y me llevan a este artículo EM: http://support.microsoft.com/default.aspx?scid=KB;EN-US;168958 que le dice cómo exportar una plantilla STL desde una DLL para satisfacer las advertencias que recibía.

El problema es, cuando agrego las siguientes líneas para eliminar las advertencias:

EXPIMP_TEMPLATE template class DECLSPECIFIER std::allocator<char>; 
EXPIMP_TEMPLATE template class DECLSPECIFIER std::basic_string< char, std::char_traits<char>, std::allocator<char> >; 

la DLL compila sin advertencias, pero cuando compilo mi EXE, el enlazador le da un ataque:

2>SampleDLL.lib(SampleDLL.dll) : error LNK2005: "public: __thiscall std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >::~basic_string<char,struct std::char_traits<char>,class std::allocator<char> >(void)" ([email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]) already defined in OtherClass.obj 
2>SampleDLL.lib(SampleDLL.dll) : error LNK2005: "public: unsigned int __thiscall std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >::size(void)const " ([email protected][email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@QBEIXZ) already defined in OtherClass.obj 

Tanto el DLL como el EXE se compilan con las mismas opciones de generación de código. Puedo usar MT en ambos o MD, y los resultados son los mismos.

Estoy incluyendo el código de un programa de muestra minimizado en caso de que haya dejado algo fuera.

Mi pregunta principal: ¿Puedo reparar los errores de LNK2005, o es seguro ignorar las advertencias de C4251?

Editar: Así que he leído un poco más, y parece que si el std :: string que utiliza la clase DLL es una variable privada que sólo se accede por funciones miembro, puede ser seguro ignora la advertencia ... ¿Algún comentario sobre esto? ¿Es este un paso en la dirección correcta?

código DLL:

#pragma once 

#include <exception> 
#include <string> 


#ifdef SAMPLEDLL_EXPORTS 
# define DECLSPECIFIER __declspec(dllexport) 
# define EXPIMP_TEMPLATE 
#else 
# define DECLSPECIFIER __declspec(dllimport) 
# define EXPIMP_TEMPLATE extern 
#endif 

//disable warnings on extern before template instantiation (per MS KB article) 
#pragma warning (disable : 4231) 
//std::basic_string depends on this allocator, so it must also be exported. 
EXPIMP_TEMPLATE template class DECLSPECIFIER std::allocator<char>; 
//std::string is a typedef, so you cannot export it. You must export std::basic_string 
EXPIMP_TEMPLATE template class DECLSPECIFIER std::basic_string< char, std::char_traits<char>, std::allocator<char> >; 
#pragma warning (default : 4231) 

class DECLSPECIFIER MyClass 
{ 
public: 
    std::string getData(); //returns 'data', body in CPP file 
private: 
    std::string data; 
    int data2; 
}; 

//in SampleDLL.cpp file... 
std::string MyClass::getData() { return data; } 

código EXE:

#include <iostream> 
#include "SampleDLL.h" 

using namespace std; 

void main() 
{ 
    MyClass class1; 

    cout << class1.getData() << endl; 

} 
+0

posible duplicado de [Exportación de clases que contienen std :: objetos (vector, mapa, etc.) desde un dll] (http: // stackoverflow.com/questions/767579/exporting-classes-containing-std-objects-vector-map-etc-from-a-dll) – Mark

+0

Mark: Leí esa pregunta, pero no parecía tener una respuesta para el problema Estoy viendo porque no menciona el problema adicional de LNK2005 que ahora tengo. – JPhi1618

Respuesta

3

Parece que está viendo el problema descrito en connect.microsoft.com.

Hay una solución sugerida allí, pero parece un poco desagradable.

Otras opciones que pueden ayudar:

  1. no exportan std :: string, en lugar de utilizar const char * en la interfaz de DLL (ver https://stackoverflow.com/a/5340065/12663)
  2. Asegúrese de que el _ITERATOR_DEBUG_LEVEL coincide para todos sus proyectos
+0

Gracias. Eso ciertamente parece ser el problema con el que me estaba encontrando. Manera de desenterrar un hilo muerto, pero una respuesta es una respuesta, y esta es la primera buena explicación que he encontrado. Espero que ayude a los demás! – JPhi1618

2

El enlace al artículo de MS que usted presentó dice que algunas clases de STL "... ya han sido exportadas por el C Runtime DLL. Por lo tanto, no puede exportarlas de su DLL". Incluyendo basic_string. Y su error de enlace dice que el símbolo basic_string "... ya está definido en OtherClass.obj". Porque el enlazador ve dos símbolos iguales en dos lugares diferentes.

+0

¿Podría describir cómo manejarlo con basic_string? –

0

Al exportar std :: STL basic_string plantilla a partir de DLL, me sale un error LNK2005

También vea 168958 de Microsoft KB artículo How to export an instantiation of a Standard Template Library (STL) class and a class that contains a data member that is an STL object. Desde el artículo:

para exportar una clase STL

  1. Tanto en el DLL y el archivo .exe, enlace con la misma versión de DLL del tiempo de ejecución C. O bien enlace tanto con Msvcrt.lib (release build) como con el enlace con Msvcrtd.lib (debug build).
  2. En la DLL, proporcione el especificador __declspec en la declaración de instanciación de la plantilla para exportar la instanciación de clase STL desde la DLL.
  3. En el archivo .exe, proporcione los especificadores extern y __declspec en la declaración de instanciación de la plantilla para importar la clase desde la DLL . Esto da como resultado una advertencia C4231 "extensión no estándar utilizada: 'extern' antes de la creación de instancias explícita de la plantilla." Puede ignorar esta advertencia .
0

tengo un truco puede arreglar esto en temp Opciones

proyecto abierto, haga clic Linker-> de línea de comandos, En las opciones del cuadro de entrada adicionales, el tipo

/FORCE:MULTIPLE 
0

Para mí todo el tema se redujo a

  • No exportar cosas STL. Ignora la advertencia. (Por lo menos hasta MSVC2013.)
  • Por supuesto, asegúrese de que cada parte se vincule con el tiempo de ejecución de C de la misma manera con respecto a la depuración/liberación, estática/dinámica.

Siempre me ha solucionado el problema hasta ahora.

Lamentablemente, no hay respuesta si no tienes control sobre el código fuente al que te gustaría vincular.

Cuestiones relacionadas