2
votes

I have a dll (my_library.dll) that exports a struct using __declspec(dllexport). Since this struct contains an std::vector<std::wstring> member, I've also exported functions for it like so:

template class __declspec(dllexport) std::allocator<std::wstring>;
template class __declspec(dllexport) std::vector<std::wstring>;

Please note that I've defined macros such that dll exports above struct and vector when compiling and they are imported (via __declspec(dllimport)) when the dll is being used by another application. The above dll builds fine.

Now this my_library.dll (and the corresponding my_library.lib) is linked to an exe (my_exe.exe). This exe has a .cpp file (exe_source.cpp) that defines a global std::vector<std::wstring> variable. This source file compiles fine. However when building this exe, I get the following error:

my_library.lib(my_library.dll) : error LNK2005: "public: __thiscall std::vector,class std::allocator

,class std::allocator,class std::allocator

::~vector,class std::allocator ,class std::allocator,class std::allocator (void)" (??1?$vector@V?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@V?$allocator@V?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@@2@@std@@QAE@XZ) already defined in exe_source.obj

What I suspect is that the my_library.dll has all std::vector<std::wstring> functions defined and exported, and using the global std::vector<std::wstring> variable in the exe_source.cpp is also resulting in definition of many std::vector<std::wstring> functions, leading to linker complaining that multiple definitions of such functions are found.

Am I understanding the error correctly?

And how to fix this?

Thanks for your time.

1
Even if you got this to link, it isn't a good idea to export C++ classes where you really have no control over their internal implementations. If your app is compiled with different compiler options, different compiler version, etc. that vector isn't going to be the same vector the DLL is using.PaulMcKenzie
@PaulMcKenzie, thanks for the suggestion. However, I think that vectors can be imported correctly, as suggested by the Microsoft article support.microsoft.com/en-us/kb/168958.AarCee
Whether it is correct or not, it isn't a good idea or a habit to get into. As the answer from @MrC64 states, it is highly brittle design choice.PaulMcKenzie
You are storing up huge amounts of trouble for the future. Ignore the advice you have been given at your peril.David Heffernan
I want to clarify that I encourage the OP to follow better design choices (as already written in my answer), like having a DLL exporting a pure C interface (C++ is fine inside the implementation of the DLL).Mr.C64

1 Answers

2
votes

First, having STL classes at DLL interfaces is a highly constraining design choice: in fact, both the DLL and the other modules using it (e.g. the EXE built by your DLL clients) must be built with the same C++ compiler version and linking to the same flavor of the CRT DLL.

Better design choices would be exporting a DLL with a pure C interface (the implementation can use C++, but you should flatten the public API to make it C), or use a COM-like approach of exporting C++ abstract interfaces, as suggested in this CodeProject article.

Assuming you are aware of that, you should be able to remove the lines:

template class __declspec(dllexport) std::allocator<std::wstring>;
template class __declspec(dllexport) std::vector<std::wstring>;

and just export the structure hosting your STL data members, for example:

MyLib.h

#pragma once

#ifndef MYLIB_API
#define MYLIB_API __declspec(dllimport)
#endif

#include <string>
#include <vector>

struct MYLIB_API MyLib_Data
{
    std::vector<std::wstring> Strings;
    // ... other stuff ...
};

MyLib.cpp

#define MYLIB_API __declspec(dllexport)
#include "MyLib.h"

// ... Implementation code ...

Note that you may receive a warning C4251, something like:

'MyLib_Data::Strings' : class 'std::vector<std::wstring,std::allocator<_Ty>>'
needs to have dll-interface to be used by clients of struct 'MyLib_Data'

but you may ignore it.