Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implications of using std::vector in a dll exported function

Tags:

c++

stl

dll

I have two dll-exported classes A and B. A's declaration contains a function which uses a std::vector in its signature like:

class EXPORT A{
 // ...
 std::vector<B> myFunction(std::vector<B> const &input);
};

(EXPORT is the usual macro to put in place _declspec(dllexport)/_declspec(dllimport) accordingly.)

Reading about the issues related to using STL classes in a DLL interface, I gather in summary:

  • Using std::vector in a DLL interface would require all the clients of that DLL to be compiled with the same version of the same compiler because STL containers are not binary compatible. Even worse, depending on the use of that DLL by clients conjointly with other DLLs, the ''instable'' DLL API can break these client applications when system updates are installed (e.g. Microsoft KB packages) (really?).

  • Despite the above, if required, std::vector can be used in a DLL API by exporting std::vector<B> like:

    template class EXPORT std::allocator<B>;
    template class EXPORT std::vector<B>;
    

    though, this is usually mentioned in the context when one wants to use std::vector as a member of A (http://support.microsoft.com/kb/168958).

  • The following Microsoft Support Article discusses how to access std::vector objects created in a DLL through a pointer or reference from within the executable (http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q172396). The above solution to use template class EXPORT ... seems to be applicable too. However, the drawback summarized under the first bullet point seems to remain.

  • To completely get rid of the problem, one would need to wrap std::vector and change the signature of myFunction, PIMPL etc..

My questions are:

  • Is the above summary correct, or do I miss here something essential?

  • Why does compilation of my class 'A' not generate warning C4251 (class 'std::vector<_Ty>' needs to have dll-interface to be used by clients of...)? I have no compiler warnings turned off and I don't get any warning on using std::vector in myFunction in exported class A (with VS2005).

  • What needs to be done to correctly export myFunction in A? Is it viable to just export std::vector<B> and B's allocator?

  • What are the implications of returning std::vector by-value? Assuming a client executable which has been compiled with a different compiler(-version). Does trouble persist when returning by-value where the vector is copied? I guess yes. Similarly for passing std::vector as a constant reference: could access to std::vector<B> (which might was constructed by an executable compiled with a different compiler(-version)) lead to trouble within myFunction? I guess yes again..

  • Is the last bullet point listed above really the only clean solution?

Many thanks in advance for your feedback.

like image 368
jrg Avatar asked May 13 '12 15:05

jrg


1 Answers

Unfortunately, your list is very much spot-on. The root cause of this is that DLL-to-DLL or DLL-to-EXE is defined on the level of the operating system, while the the interface between functions is defined on the level of a compiler. In a way, your task is similar (although somewhat easier) to that of client-server interaction, when the client and the server lack binary compatibility.

The compiler maps what it can to the way the DLL importing and exporting is done in a particular operating system. Since language specifications give compilers a lot of liberty when it comes to binary layout of user-defined types and sometimes even built-in types (recall that the exact size of int is compiler-dependent, as long as minimal sizing requirements are met), importing and exporting from DLLs needs to be done manually to achieve binary-level compatibility.

When you use the same version of the same compiler, this last issue above does not create a problem. However, as soon as a different compiler enters the picture, all bets are off: you need to go back to the plainly-typed interfaces, and introduce wrappers to maintain nice-looking interfaces inside your code.

like image 141
Sergey Kalinichenko Avatar answered Oct 23 '22 20:10

Sergey Kalinichenko