2

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.

5
  • 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. Commented Nov 19, 2015 at 10:39
  • @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. Commented Nov 19, 2015 at 10:42
  • 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. Commented Nov 19, 2015 at 10:43
  • You are storing up huge amounts of trouble for the future. Ignore the advice you have been given at your peril. Commented Nov 19, 2015 at 12:20
  • 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). Commented Nov 21, 2015 at 0:40

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

11 Comments

But then will I be able to use the vector in my_exe.exe? Although I don't change it, I do use this vector in my_exe.exe. Update: not using the template class statements results in unresolved externals errors where I iterate the vector member in the exe.
Assuming your exe is built with the same VC++ compiler version and links with the same flavor of the CRT, yes. Just try it.
You must be doing something wrong: I tried a simple repro with the above code snippet and an EXE iterating through the vector via a range-based for, and the strings are displayed correctly. (Of course, make sure to link your EXE with the .lib file generated by the linker and associated to your DLL.)
I have a getter function member in the struct that returns this vector, I use this in the exe and assign it to a local vector variable and use iterator to iterate the vector.
@AarCee: Just tried adding a simple getter and it works fine as well.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.