Search code examples
c++builder

How to avoid an Access Violation when adding a destructor to a DataModule?


Using C++Builder, I created a new project, added a DataModule to the project, added a reference to that DataModule in the MainForm. I ran it and closed the MainForm. Result – no problem.

Then, I added a destructor to the DataModule, recompiled, and it ran fine until I closed the MainForm, and then I got an Access Violation.

What does it take to be able to add a destructor to a DataModule?

Here is the code I came up with:

DataMod2.h

#ifndef DataMod2H
#define DataMod2H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
//---------------------------------------------------------------------------
class TDataModule2 : public TDataModule
{
__published:    // IDE-managed Components
private:    // User declarations
public:     // User declarations
    __fastcall TDataModule2(TComponent* Owner);
    ~TDataModule2();
};
//---------------------------------------------------------------------------
extern PACKAGE TDataModule2 *DataModule2;
//---------------------------------------------------------------------------
#endif

DataMod2.cpp

#pragma hdrstop

#include "DataMod2.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma classgroup "FMX.Controls.TControl"
#pragma resource "*.dfm"
TDataModule2 *DataModule2;
//---------------------------------------------------------------------------
__fastcall TDataModule2::TDataModule2(TComponent* Owner)
    : TDataModule(Owner)
{
}
//---------------------------------------------------------------------------
TDataModule2::~TDataModule2() {

}

Unit2.h

#ifndef Unit2H
#define Unit2H
#include "DataMod2.h"
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <FMX.Controls.hpp>
#include <FMX.Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    // IDE-managed Components
private:    // User declarations
    TDataModule2 * dataMod;
public:     // User declarations
    __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

Unit2.cpp

#include <fmx.h>
#pragma hdrstop

#include "Unit2.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.fmx"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
    dataMod = new TDataModule2(Form1);
}
//---------------------------------------------------------------------------

Solution

  • Overriding the base class destructor requires matching the entire signature of the destructor, including the calling convention. The DataModule derives from TObject, and TObject's destructor looks like this:

    __fastcall virtual ~TObject();
    

    Your DataModule destructor is missing the __fastcall calling convention:

    class TDataModule2 : public TDataModule
    {
        ...
        __fastcall ~TDataModule2();
    };
    
    __fastcall TDataModule2::~TDataModule2() {
    
    }
    

    Also, in your TForm1 constructor, you should be using the this pointer as the DataModule's Owner rather than using the global Form1 variable:

    __fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
    {
        dataMod = new TDataModule2(this);
    }