Export classes containing std :: objects (vector, map, etc.) from dll

I am trying to export classes from DLLs containing objects such as std :: vectors and std :: strings - the whole class is declared as a dll export via:

class DLL_EXPORT FontManager { 

The problem is that for members of complex types, I get this warning:

warning C4251: 'FontManager :: m__fonts': class 'std :: map <_Kty, _Ty>' must have a dll interface that will be used by clients of the 'FontManager' class with [_Kty = std :: string, _Ty = tFontInfoRef]

I can remove some warnings by putting the following class declaration in front of them, even if I do not change the type of the member variables themselves:

 template class DLL_EXPORT std::allocator<tCharGlyphProviderRef>; template class DLL_EXPORT std::vector<tCharGlyphProviderRef,std::allocator<tCharGlyphProviderRef> >; std::vector<tCharGlyphProviderRef> m_glyphProviders; 

It seems that the front declaration injects DLL_EXPORT when the member compiles, but is it safe? Does this really change something when the client compiles this header and uses the std container on its side? Will all future uses of such a DLL_EXPORT container (and possibly not inline?) Do this? And does it really fix the issue the warning warns about?

Is this warning something I have to worry about, or would it be better to disable it as part of these constructs? Clients and dlls will always be built using the same set of libraries and compilers, and these are header-only classes ...

I am using Visual Studio 2003 with the standard STD library.

---- Update ----

I would like to target you more, because, as I see, the answers are general, and here we are talking about std containers and types (for example, std :: string) - maybe the question is really like this:

Is it possible to disable the warning for standard containers and types available to both the client and the DLL through the same library headers, and treat them the same way as we will consider an int or any other built-in type? (It seems he is working correctly on my side.) If these were the conditions under which we can do this?

Or maybe the use of such containers is forbidden, or at least very carefully to make sure that no assignment operators, copy constructors, etc. will not be included in the dll client?

In general, I would like to know if you feel that the design of a dll interface in which such objects (and, for example, using them to return material to the client as return types) is a good idea or not, and why would I for example, have a "high level" interface for this functionality ... perhaps the best solution is what Neil Butterworth suggested - creating a static library?

+50
c ++ dll visual-studio
Apr 20 '09 at 9:38
source share
12 answers

When you touch a member in your class from the client, you need to provide a DLL interface. A DLL interface means that the compiler creates a function in the DLL itself and makes it available.

Since the compiler does not know which methods are used by clients of the DLL_EXPORTED class, it must ensure that all methods are exported by the dll. It must ensure that all participants that customers can contact must also export their functions. This happens when the compiler warns you about non-exported methods and the linker of the client sending the errors.

Not every member should be marked with dll-export, for example. private members not related to customers. Here you can ignore / disable warnings (beware of the compiler generated by dtor / ctors).

Otherwise, participants must export their methods. Forward declaring them using DLL_EXPORT does not export the methods of these classes. You must mark the corresponding classes in your compilation unit as DLL_EXPORT.

What it boils down to ... (not for dll-exported members)

  • If you have members that cannot / cannot be used by clients, turn off the warning.

  • If you have members that should be used by clients, create a dll export wrapper or create indirect methods.

  • To reduce the number of externally visible elements, use approaches such as the PIMPL idiom .




 template class DLL_EXPORT std::allocator<tCharGlyphProviderRef>; 

This creates an instance of the template specialization in the current compilation unit. Thus, it creates the std :: allocator methods in the dll and exports the appropriate methods. This does not work for specific classes, as it is just an instance of template classes.

+42
Apr 20 '09 at 10:33
source share

This warning tells you that users of your DLL will not have access to your container member variables across the DLL boundary. Explicitly exporting them makes them available, but is it a good idea?

In general, I would not export std containers from your DLL. If you can absolutely guarantee that your DLL will be used with the same version of runtime and compiler that you will be safe. You must ensure that the allocated memory in your DLL is freed using the same memory manager. Otherwise, at best, assert at runtime.

Therefore, do not expose containers directly across DLL boundaries. If you need to expose container elements, do this using access methods. In case you have provided, separate the interface from the implementation and expose the inteface at the DLL level. Using std containers is an implementation detail that the client of your DLL should not receive.

Alternatively, do what Neil offers and create a static library instead of a DLL. You lose the ability to load the library at runtime, and your library consumers must reconnect at any time when you change your library. If these are the trade-offs you can live with, the static library will at least help you overcome this problem. I will continue to claim that you overly detailed implementation details, but this may make sense for your specific library.

+15
May 01 '09 at 2:01 a.m.
source share

There are other problems.

Some STL containers are "safe" for export (for example, a vector), and some are not (for example, maps).

A card, for example, is unsafe because it (in any case, in the MS STL distribution) contains a static member named _Nil, the value of which is compared at iteration to check the end. Each module compiled using STL has a different value for _Nil, so a map created in one module cannot be iterable from another module (it never detects an end and does not explode).

This applies even if you are statically referencing lib since you can never guarantee that _Nil will be (it is not initialized).

I believe STLPort does not.

+6
Aug 05 2018-10-10 at
source share

The best way to find this scenario is:

create your library, name it using the compiler and stl versions included in the library name, just like boost libraries.

examples:

- FontManager-msvc10-mt.dll for the dll version specific to the MSVC10 compiler, stl by default.

- FontManager-msvc10_stlport-mt.dll for the dll version specific to the MSVC10 compiler, with the stl port.

- FontManager-msvc9-mt.dll for dll version specific to MSVC 2008 compiler with standard stl

- libFontManager-msvc10-mt.lib for the static version of lib specific to the MSVC10 compiler, stl by default.

after this template you will avoid the problems associated with various stl implementations. remember that the stl implementation in vc2008 is different from the stl implementation in vc2010.

See an example using boost :: config library:

 #include <boost/config.hpp> #ifdef BOOST_MSVC # pragma warning( push ) # pragma warning( disable: 4251 ) #endif class DLL_EXPORT FontManager { public: std::map<int, std::string> int2string_map; } #ifdef BOOST_MSVC # pragma warning( pop ) #endif 
+6
Mar 06 '11 at 1:20
source share

One of the alternatives, which, apparently, is of little interest to anyone, is not to use the DLL in general, but to link statically with the static .LIB library. If you do this, all export / import problems will disappear (although you will still have problems with names if you use different compilers). Of course, you lose the capabilities of the DLL architecture, such as loading functions at runtime, but in many cases it can be a small price.

+5
Apr 20 '09 at 10:47
source share

Found in this article . In short, Aaron has the "real" answer above; Do not expose standard containers to library boundaries.

+4
Aug 04 '09 at 13:03
source share

Although this thread is pretty old, I recently discovered a problem that made me think again about the presence of patterns in my exported classes:

I wrote a class that had a private member like std :: map. Everything worked well enough until it was compiled in release mode. Even if it is used in the build system, which ensures that all compiler settings are the same for all purposes. The card was completely hidden and nothing was directly affected by customers.

As a result, the code just worked in release mode. I believe that different binary instances of std :: map were created for the implementation and the client code.

I assume that C ++ Standard does not say anything about how this should be handled for exported classes, since it depends a lot on the compiler. Therefore, I suggest that the biggest portability rule is simply exposing the interfaces and making the most of the PIMPL idiom.

Thanks for any enlightenment.

+2
Nov 21 '09 at 20:16
source share

In such cases, consider using the pimpl idiom. Hide all complex types in one void *. The compiler usually does not notice that your members are private and all methods are included in the DLL.

+1
Apr 20 '09 at 10:57
source share

Export classes containing std :: objects (vector, map, etc.) from dll

Also see Microsoft article KB 168958 How to export an instance of a standard template library (STL) class and a class that contains a data item that is an STL object . From the article:

Export STL Class

  • Both in the DLL and in the .exe file, the link to the same version of the DLL is version C. Either link both to Msvcrt.lib (release build) or link both to Msvcrtd.lib (debug build).
  • In the DLL, specify the __declspec qualifier in the template creation declaration to export an instance of the STL class from the DLL.
  • In the .exe file, provide the extern and __declspec qualifiers in the template creation declaration for importing the class from the DLL. This leads to a warning against using the non-standard extension C4231: 'extern' before explicitly instantiating the template. "You can ignore this warning.

and

Export a class containing a data item that is an STL object

  • Both in the DLL and in the .exe file, the link to the same version of the DLL is version C. Either link both to Msvcrt.lib (release build) or link both to Msvcrtd.lib (debug build).
  • In the DLL, specify the __declspec qualifier in the template creation declaration to export an instance of the STL class from the DLL.

    NOTE. You cannot skip step 2. You must export an instance of the STL class that is used to create the data item.
  • In the DLL, specify the __declspec qualifier in the class declaration to export the class from the DLL.
  • In the .exe file, specify the __declspec qualifier in the class declaration for importing the class from the DLL. If the class you export has one or more base classes, then you must export the base classes.

    If the class that you are exporting contains data elements that are related to the class type, then you should export the data element classes as well.
+1
Apr 08 '15 at 5:05
source share

If you are using a DLL, initialize all objects in the "DLL PROCESS ATTACH" event and export a pointer to its classes / objects.
You can provide certain functions for creating and destroying objects and functions to get a pointer to the created objects so that you can encapsulate these calls in the access wrapper class in the included file.

0
May 01 '09 at 1:32
source share

none of the workarounds permissible with MSVC due to static data elements inside template classes such as stl containers

each module (dll / exe) gets its own copy of each static definition ... wow! this will lead to terrible things if you somehow "export" such data (as "indicated" above), so do not try to do this at home.

see http://support.microsoft.com/kb/172396/en-us

0
Apr 20 '10 at 20:10
source share

The best approach to use in such scenarios is to use the PIMPL design pattern.

0
Oct 07 '15 at 4:30
source share



All Articles