3

I am trying to make a DLL file compatible with different compiler configurations (Debug, Release,..). In order to make sure that an object is removed the right way I managed to write a pointer wrapper class that uses a compiled delete operator whenever I take an object of the DLL and run out of scope.

I am perfectly fine with this but my program crashes when I try to delete memory that I allocated in the very same method/program.

Here is some sample code compiled in a standard Release mode:

header

template <typename T>
class API mwCompatibleObject
{
public:

    //! Constructor
    mwCompatibleObject();

    //! Destructor
    virtual ~mwCompatibleObject();
};

source code

template < typename T >
mwCompatibleObject< T >::mwCompatibleObject() {}

template <typename T>
mwCompatibleObject<T>::~mwCompatibleObject() {}

Note: API is defined as export/import.

Now I use this very class in a Debug mode application where I create an instance and delete it right away.

mwCompatibleObject<double> * obj = new mwCompatibleObject<double>();
delete obj;

Executing the delete operator gives an access violation at mlock.c line 376.

Here is a copy of the callstack:

ntdll.dll!7721e3be()    
[Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll]
msvcr80d.dll!_unlock(int locknum=4)  Line 376   C
msvcr80d.dll!_heap_alloc_dbg(unsigned int nSize=0, int nBlockUse=2968120, const char * szFileName=0x2e2ed26c, int nLine=1638180)  Line 477 + 0x7 bytes  C++
msvcr80d.dll!_heap_alloc_dbg(unsigned int nSize=0, int nBlockUse=2968120, const char * szFileName=0x2e2ed26c, int nLine=1638180)  Line 474 + 0xc bytes  C++
00300000()  
msvcr80d.dll!malloc(unsigned int nSize=2968120)  Line 154 + 0x15 bytes  C++
5axutil.dll!100b5d09()  
Integrator3.exe!main()  Line 54 + 0x34 bytes    C++

I can't jump into that line or anything but I managed to get a look at the Assembler code which proves my observation that it has to do with the destructor.

Is there a general problem with virtual functions/destructors when trying to make a DLL compatible?

user7116
  • 63,008
  • 17
  • 141
  • 172
Marcel Bonzelet
  • 238
  • 2
  • 13
  • export/import does not make sense for a template. `mwCompatibleObject` becomes defined in your calling application when you included the header file. – Blazes May 27 '11 at 14:46
  • Did you build the sources in the target project that use your dll ? You can try to put the templated implementation (your source file) in your header file just above the declaration of your class. – Thomas Vincent May 27 '11 at 14:46
  • If you only compile the code that you posted, does it still crash? I bet the problem is heap corruption elsewhere in your program. – bk1e May 27 '11 at 14:48
  • are your function bodies in the header file? if not, that may cause that crush – Raiv May 27 '11 at 14:57
  • One additional comment about memory and DLLs - memory allocated in the DLL can only be deleted from within the DLL. I don't think this is happening in your case, but it is something to be aware of. – Blazes May 27 '11 at 15:02

1 Answers1

4

You can't export a template definition as the compiler generates the types based on usage of the template. You simply inline them in the header file or you can do something like this but that requires declaring your template instantiation upfront.

Also note in C++ prefer new and delete over malloc and free functions from C especially if you actually want constructors and destructors to be called.

Edit:

I would seriously consider inlining of the template preferable to any attempt to export. Also I failed to note originally that virtual destructors are only needed if your class will be a base class or contain virtual methods. Why have a vtable with nothing in it?

template <typename T>
class mwCompatibleObject // no need for export if inlined in header
{
public:
    //! Constructor
    mwCompatibleObject() {}
    //! Destructor (don't need virtual unless it's a base class or has virtual methods)
    ~mwCompatibleObject() {}

    //! Some public method
    void DoSomething(const T& withSomething)
    {
        // ... yata yata
    }
private:
    T m_member;
};

Further Edit:

I just found out that exporting template support will be completely removed (not deprecated, removed) from the new C++ standard when it is finalized. Inline templates in header files will be the only solution that compilers will implement and allow in the very near future, so get used to writing them this way now. See Herb Sutter's Questions & Answers about C++0x

AJG85
  • 15,849
  • 13
  • 42
  • 50
  • Thank you all for your answers. I forgot to post the explicit instantiation code in the source file. It makes it possible to use the template for the types float and double, so don't worry about the export/import, it is surely used. And I might add that this code is comletely stand-alone. I didn't add anything else and tried to narrow down the problem by using only necessary code while still crashing. Today I tried some other cases and figured out, that in some cases it may crash when API is only defined when exported. Is there a chance that this is my source of error? – Marcel Bonzelet Jun 09 '11 at 07:12
  • You started to lose me there at the end ... I would just inline the template if you are still having issues. See my edit above. – AJG85 Jun 09 '11 at 15:26
  • I finally got it! The source of error was, as expected, the missing dllimport. I don't know why but it is allowed to import from a dll without explicit use of dllimport, that's why I didnt notice it is missing. Using it now seems to run with the virtual tables created by dllexport. Thanks for your effort! – Marcel Bonzelet Jun 22 '11 at 07:14