64

I'm trying to make my library exportable as a DLL but I'm getting a lot of these warnings for one specific class that uses std::vector:

template <typename T>
class AGUI_CORE_DECLSPEC AguiEvent {
    typedef void (*AguiCallbackFptr)(T arg, AguiWidget* sender);
std::vector<AguiCallbackFptr> events;
public:
    void call(AguiWidget* sender, T arg) const;
    void addHandler(AguiCallbackFptr proc);
    void removeHandler(AguiCallbackFptr proc);
    void removeHandler();
    AguiEvent();
};

I get warnings like these:

Warning 57 warning C4251: 'AguiEvent::events' : class 'std::vector<_Ty>' needs to have dll-interface to be used by clients of class 'AguiEvent'

I tried to find how to do this properly but MSDN's documentation is very Windows Only, and I need this to be cross platform so that it only does MS specific stuff when AGUI_CORE_DECLSPEC is in fact defined.

What should I do to get rid of these warnings?

Thanks

jmasterx
  • 52,639
  • 96
  • 311
  • 557
  • Related Core Issue: http://stackoverflow.com/questions/767579/exporting-classes-containing-std-objects-vector-map-etc-from-a-dll – Will Bickford Feb 14 '12 at 17:05

4 Answers4

43

Exporting from a DLL is platform-specific. You will have to fix this for Windows (basically use declspec(dllexport/dllimport) on the instantiated class template) and encapsulate the required code in your Windows-specific preprocessor macro.

My experience is that exporting STL classes from DLLs on Windows is fraught with pain, generally I try to design the interface such that this is not needed.

Steve Townsend
  • 53,498
  • 9
  • 91
  • 140
  • 14
    Any insight on why I am still getting this error with respect to private class variables? The class is exported, but I would expect private methods and objects to not trip this warning. . . – meawoppl Jan 24 '14 at 18:10
  • 5
    Probably because the size of the privates impacts on the size of the exported class. It's not part of the public interface in that it's not directly accessible, but still forms part of it if it's in an exported class as a member by value. Try holding it by pointer or hiding behind a pimpl. (All of this is just a guess). – Ben Hymers Jan 26 '14 at 18:08
  • 1
    link broken again – chtenb May 01 '18 at 10:00
  • 1
    I cannot find the content - it looks like it is really gone this time. Replaced it with a cached copy. – Steve Townsend May 01 '18 at 11:05
40

One fix is relying on dynamic allocation/deallocation of the STL structures. So:

class EXPORTED ExportedClass
{
private:
    std::vector<int> *_integers;
public:
    ExportedClass()
    {
        _integers = new std::vector<int>();
    }
    ~ExportedClass()
    {
        delete _integers;
    }
};

won't give any warning and it's more safe in case you are distributing the same binary (the dll) that has to be used with different version of the compiler that may has different versions of the STL. In this way you have 100% guarantee that sizeof(ExportedClass) is always the same.

ceztko
  • 14,736
  • 5
  • 58
  • 73
  • I guess unique_ptr could be used in this case as well? To get rid of the new and delet, I mean. – AzP Jan 23 '17 at 09:53
  • 2
    @AxP It could be used but you could have similar problems when distributing a shared library compiled with a c++ standard library that is ABI incompatible on shared pointers than the one present on the target system – ceztko Jun 28 '17 at 10:26
13

You could just export the members, which the dll-clients need to access. To do this remove the export declaration from the class declaration and add it to each individual member function you want to export.

EDIT:

In your case you should probably not try to export the class (leave out AGUI_CORE_DECLSPEC) since it is a template class. Provide all methods in your header as inline and it will work.

If you do not want this, some compilers provide a special way to export template classes. But you will have to specify the template parameter for this.

frast
  • 2,700
  • 1
  • 25
  • 34
  • 1
    I only had problems with private exports and I declspec'ed the whole class. Your advice did it! I then declspec'ed the methods explicitly in the header file and it worked. – ChrisoLosoph Jul 27 '21 at 14:03
1

The usual method of dealing with platform specific stuff like this is to try and restrict all platform specific settings to a handful of low level files/classes, and then use #defines and #ifdef/#ifndef preprocessor directives to add/replace platform specific variations.

To effectively implement this, you may need an abstraction layer. For example a production system I worked on in the 1990s had a "File System" library. This presented a common interface to the applications and production code, but had to rely on a few platform-specific files. As well as making it easier to compile and maintain, it also made it easier to port to new platforms. A new file hardware vendor or OS flavour? Simply add the settings to the include files and add new directives accordingly.

winwaed
  • 7,645
  • 6
  • 36
  • 81