Board index » cppbuilder » Problem with delete vs FreeInstance()

Problem with delete vs FreeInstance()


2006-09-19 11:46:13 PM
cppbuilder48
Hi:
In code below, I create the adoRecordSet with the new operator.
However, delete adoRecordSet throws an exception while freeInstance()
does not.
Per Help:
********************************
FreeInstance()
Deallocates memory allocated by a previous call to the NewInstance method.
virtual void __fastcall FreeInstance();
Description
All destructors call FreeInstance automatically to deallocate memory
that was allocated by overriding NewInstance.
Do not call FreeInstance directly. FreeInstance should be overridden if
NewInstance was overridden to change the way the objectís instance data
was allocated. <------------------------------
Like NewInstance, FreeInstance uses the value returned from InstanceSize
to deallocate the object's memory.
*********************************
Why would delete throw an exception reporting invalid pointer operation
and NewInstance works fine?
Any help appreciated.
Thanks.
--------------------------------------------------------------------------------------------------------------
TSCRObject *adoRecordSet = new TSCRObject();
ICRDataSource *tInterface;
String eMessage;
trADOReports->StartTransaction();
qrADOReports->Open();
if (CrpeADO->HasSavedData)
CrpeADO->DiscardSavedData = true;
try
{
adoRecordSet->SetDataSet(qrADOReports);
tInterface = *adoRecordSet;
CrpeADO->Tables->Retrieve();
CrpeADO->Tables[0].DataPointer = &tInterface;
CrpeADO->Execute();
}
catch(...)
{
Screen->Cursor = crDefault;
delete adoRecordSet; //->FreeInstance();
if (CrpeADO->LastErrorString != "")
{
eMessage = ("There was an error running the report. The "
"report code was " +
IntToStr(CrpeADO->LastErrorNumber));
eMessage = eMessage + " and the message was " +
CrpeADO->LastErrorString;
ShowMessage(eMessage);
if (PrintForm != NULL)
{
delete PrintForm;
PrintForm = NULL;
}
// return;
}
else
throw;
}
Screen->Cursor = crDefault;
while (!PrintWindowClosed)
Application->ProcessMessages();
delete adoRecordSet; //->FreeInstance();
trADOReports->Commit();
if (PrintForm != NULL)
{
delete PrintForm;
PrintForm = NULL;
}
 
 

Re:Problem with delete vs FreeInstance()

"MrT" < XXXX@XXXXX.COM >wrote in message
Quote
In code below, I create the adoRecordSet with the new operator.

However, delete adoRecordSet throws an exception while
freeInstance() does not.
'delete' calls FreeInstance() internally. It is very unlikely that
FreeInstance() would succeed where 'delete' fails.
Quote
Why would delete throw an exception reporting invalid pointer
operation and NewInstance works fine?
You are probably calling 'delete' on an invalid pointer to begin with Your
use of the ICRDataSource interface is very suspicious to me. Interfaces are
reference counted. Because you are not incrementing the reference count
when obtaining the interface, its reference count is likely falling to zero
too soon and freeing the RecordSet before you are actually done using it.
Gambit
 

Re:Problem with delete vs FreeInstance()

Hi:
Thanks.
Remy Lebeau (TeamB) wrote:
Quote
"MrT" < XXXX@XXXXX.COM >wrote in message
news: XXXX@XXXXX.COM ...


>In code below, I create the adoRecordSet with the new operator.
>
>However, delete adoRecordSet throws an exception while
>freeInstance() does not.


'delete' calls FreeInstance() internally. It is very unlikely that
FreeInstance() would succeed where 'delete' fails.
delete throws invalid pointer, FreeInstance sails through without
exception.
Quote


>Why would delete throw an exception reporting invalid pointer
>operation and NewInstance works fine?
(typo FreeInstance)

You are probably calling 'delete' on an invalid pointer to begin with Your
use of the ICRDataSource interface is very suspicious to me.
Interfaces are reference counted. Because you are not incrementing the reference count
when obtaining the interface, its reference count is likely falling to zero
too soon and freeing the RecordSet before you are actually done using it.
But why would that not occur with a call to FreeInstance()?
Quote


Gambit


 

{smallsort}

Re:Problem with delete vs FreeInstance()

Hi:
Further:
Remy Lebeau (TeamB) wrote:
Quote
"MrT" < XXXX@XXXXX.COM >wrote in message
news: XXXX@XXXXX.COM ...


>In code below, I create the adoRecordSet with the new operator.
>
>However, delete adoRecordSet throws an exception while
>freeInstance() does not.


'delete' calls FreeInstance() internally. It is very unlikely that
FreeInstance() would succeed where 'delete' fails.


>Why would delete throw an exception reporting invalid pointer
>operation and NewInstance works fine?


You are probably calling 'delete' on an invalid pointer to begin with Your
use of the ICRDataSource interface is very suspicious to me. Interfaces are
reference counted. Because you are not incrementing the reference count
when obtaining the interface, its reference count is likely falling to zero
too soon and freeing the RecordSet before you are actually done using it.


Gambit


So according to this the ref count is incremented automatically.
If calling delete gets an invalid pointer, so should call FreeInstance
on the object unless it is ignored. If so then I should call neither!
-----------------------------------------
Allocates memory for each instance of an interfaced object.
typedef TMetaClass* TClass;
virtual TObject* __fastcall NewInstance(TClass cls);
Description
All constructors call NewInstance automatically. NewInstance calls
InstanceSize to determine how much memory to allocate from the heap to
contain a particular instance. Do not call NewInstance directly.
TInterfacedObject overrides NewInstance to increment the reference count
when a new instance is created. This prevents any constructor from
accidentally deleting the instance due to a RefCount of zero. The
AfterConstruction method decrements the value of RefCount after all
constructors have executed.
-------------------------------------------
Indicates the number of interface pointers currently dependent upon the
COM object.
__property int RefCount = { read=FRefCount };
Description
RefCount defines the lifetime of the object. When RefCount is zero, the
object is destroyed.
RefCount is incremented by calls to the IUnknown method AddRef and
decremented by the IUnknown method Release.
--------------------------------------------
---------------------------------------------
namespace Crdatasourcelib_tlb
{
//-- type declarations
-------------------------------------------------------
__interface ICRDataSource;
typedef System::DelphiInterface<ICRDataSource>_di_ICRDataSource;
__interface INTERFACE_UUID("{F4ED51D0-E0D5-11D1-92B3-00A0C92765B4}")
ICRDataSource : public IUnknown
 

Re:Problem with delete vs FreeInstance()

"MrT" < XXXX@XXXXX.COM >wrote in message
Quote
So according to this the ref count is incremented automatically.
Read the description again. NewInstance() increments the reference count,
and AfterConstruction decrements it. By the time the constructor has
exited, the reference count has fallen back to zero again. Which is fine as
long as the reference count variable is being incremented/decremented
directly instead of via AddRef() and Release() (since Release() will free
the object).
On the other hand, what exactly does the following code do with the
interface pointer?
CrpeADO->Tables[0].DataPointer = &tInterface;
CrpeADO->Execute();
When the RecordSet is created, it has a reference count of 0 or 1. If the
Table calls Release() on the interface without a cooresponding AddRef(), the
reference count is likely falling back to zero again and the object gets
freed.
Gambit
 

Re:Problem with delete vs FreeInstance()

"MrT" < XXXX@XXXXX.COM >wrote in message
Quote
ICRDataSource *tInterface;
Try changing that declaration to the following, and see if the problem
continues:
_di_ICRDataSource tInterface
Gambit
 

Re:Problem with delete vs FreeInstance()

Remy Lebeau (TeamB) wrote:
Quote
"MrT" < XXXX@XXXXX.COM >wrote in message
news: XXXX@XXXXX.COM ...


>So according to this the ref count is incremented automatically.


Read the description again. NewInstance() increments the reference count,
and AfterConstruction decrements it. By the time the constructor has
exited, the reference count has fallen back to zero again. Which is fine as
long as the reference count variable is being incremented/decremented
directly instead of via AddRef() and Release() (since Release() will free
the object).

On the other hand, what exactly does the following code do with the
interface pointer?

CrpeADO->Tables[0].DataPointer = &tInterface;
CrpeADO->Execute();

When the RecordSet is created, it has a reference count of 0 or 1. If the
Table calls Release() on the interface without a cooresponding AddRef(), the
reference count is likely falling back to zero again and the object gets
freed.


Gambit


Applies to
Tables
Declaration
property DataPointer: Pointer;
Description
The DataPointer property, along with the Bytes and Tag properties are
part of the ADO/CDO support that has been added to the Tables class with
the 7.x.0.20 release of the Crystal Reports VCL. DataPointer should
point to the address of a valid Data Object RecordSet, such as an Active
Data Object (ADO) RecordSet, or the Crystal Data Object (CDO) RecordSet.
There are two ways of using Data Objects in Delphi. The first, easiest,
and recommended way is to import the Type Library and use the
Delphi-generated header file for all declarations. This method is
described and illustrated in the following two pages:
The Crystal Data Object (CDO)
The Active Data Object (ADO)
The other method is to use OleVariant variables instead of the
declarations contained in the Type Library. This involves one extra
layer of communication and requires an extra line of code to obtain the
actual address of the RecordSet to pass to the DataPointer property.
 

Re:Problem with delete vs FreeInstance()

Remy Lebeau (TeamB) wrote:
Quote
"MrT" < XXXX@XXXXX.COM >wrote in message
news: XXXX@XXXXX.COM ...


>ICRDataSource *tInterface;


Try changing that declaration to the following, and see if the problem
continues:

_di_ICRDataSource tInterface


Gambit


Hi:
Same thing. Back to original. The reason I am investigating this is
that sometime when I close app I get error message saying process
terminated and Dr. Watson did not attach(?). Seems to be very erratic
after running some crystal reports.
 

Re:Problem with delete vs FreeInstance()

"MrT" < XXXX@XXXXX.COM >wrote in message
Quote
DataPointer should point to the address of a valid Data Object
RecordSet, such as an Active Data Object (ADO) RecordSet,
or the Crystal Data Object (CDO) RecordSet.
In that case, the statement:
CrpeADO->Tables[0].DataPointer = &tInterface;
Should probably be this instead:
CrpeADO->Tables[0].DataPointer = tInterface;
Notice the removal of the '&' operator. It wants a pointer to the ADO
RecordSet itself, not a pointer to a pointer to a RecordSet.
Gambit
 

Re:Problem with delete vs FreeInstance()

Remy Lebeau (TeamB) wrote:
Quote
"MrT" < XXXX@XXXXX.COM >wrote in message
news: XXXX@XXXXX.COM ...


>DataPointer should point to the address of a valid Data Object
>RecordSet, such as an Active Data Object (ADO) RecordSet,
>or the Crystal Data Object (CDO) RecordSet.


In that case, the statement:

CrpeADO->Tables[0].DataPointer = &tInterface;

Should probably be this instead:

CrpeADO->Tables[0].DataPointer = tInterface;

Notice the removal of the '&' operator. It wants a pointer to the ADO
RecordSet itself, not a pointer to a pointer to a RecordSet.


Gambit


Delphi:
The @ operator returns the address of a variable, or of a function,
procedure, or method; that is, @ constructs a pointer to its operand.
The sample code from Crystal is:
C++
Referencing operator ( & )
Use the reference operator to pass the address of a pointer to a
function outside of main().
I had thought that & and @ were analogous. Never had a problem with
conversions.
If incorrect, why does it work fine? No compiler warnigns etc.
Thanks.
procedure PreviewReport;
begin
{ Open the Report }
Crpe1.ReportName := 'AdoSample.rpt';
Crpe1.DiscardData;
{Get Subreport information}
Crpe1.Subreports.Retrieve;
{Set VCL to main Report}
Crpe1.Subreports[0];
{Retrieve the Tables}
Crpe1.Tables.Retrieve;
{Attach the ADO Recordset to the main Report Table}
Crpe1.Tables[0].DataPointer := @adoRs1; <--------------
{Set VCL to first Subreport}
Crpe1.Subreports[1];
{Retrieve the Subreport Tables}
Crpe1.Tables.Retrieve;
{Attach the second ADO Recordset to the Subreport Table}
Crpe1.Tables[0].DataPointer := @adoRs2;
{Set VCL back to main Report}
Crpe1.Subreports[0];
{Run the Report}
Crpe1.Execute;
end;
 

Re:Problem with delete vs FreeInstance()

MrT < XXXX@XXXXX.COM >writes:
Quote

delete throws invalid pointer, FreeInstance sails through without
exception.
(I'm not sure what "throws invalid pointer" actually means,
so I'm guessing between a few possibilities.)
Just to be clear, delete does not throw exceptions. It invokes the
object's destructor and releases the memory back to the memory
manager. If you're getting an exception, it's from the destructor of
the object being destroyed.
Another possibility, however, is that Borland chose to convert certain
OS "exceptions" into C++ exceptions. So if you have an invalid
pointer, and you try to delete it again, you get undefined behavior,
but they may catch the os notification, convert it into a C++
exception, and allow your program to continue along its way. The
state of your program may be corrupted, and you might be fooled into
thinking that delete actually threw the exception, but in fact it
didn't.
--
Chris (TeamB);
 

Re:Problem with delete vs FreeInstance()

"MrT" < XXXX@XXXXX.COM >wrote in message
Quote
I had thought that & and @ were analogous.
They are.
Quote
If incorrect, why does it work fine? No compiler warnigns etc.
Because there is nothing from the compiler to complain about. The property
in question accepts a raw memory pointer. Whether you use '&' or not, you
are still passing a memory address to the property, so the compiler is
happy.
Quote
{Attach the ADO Recordset to the main Report Table}
Crpe1.Tables[0].DataPointer := @adoRs1; <--------------
In that case, the'&' is correct to use (though odd that they would require
that approach).
In any case, because Tables is itself a pointer to a class, and assuming
that "Tables[0]" returns a pointer (which is almost a certainty in Delphi),
then this statement:
CrpeADO->Tables[0].DataPointer = &tInterface;
Would have to be this instead:
CrpeADO->Tables->Table[0]->DataPointer = &tInterface;
Or:
CrpeADO->Tables->Items[0]->DataPointer = &tInterface;
Depending on what the actual array property is named. You are trying to
apply the'[]' operator on the wrong pointer in your C++ code. In Delphi, a
class can have a "default" property. Applying the '[]' operator on a class
pointer in Delphi invokes that class's default property, so you do not have
to reference it by name explicitially. In C++, however, you cannot do that,
so you have to reference the default property by name explicitially instead.
Unless you are using BCB 6 or BDS, in which case you can deference the class
pointer in order to invoke the '[]' operator that Borland provides for
accessing the default property:
(*(CrpeADO->Tables))[0]->DataPointer = &tInterface;
Gambit
 

Re:Problem with delete vs FreeInstance()

Hi:
I am getting confuseder and confusder!!!!(Hah)
Remy Lebeau (TeamB) wrote:
Quote
"MrT" < XXXX@XXXXX.COM >wrote in message
news: XXXX@XXXXX.COM ...


>I had thought that & and @ were analogous.


They are.


>If incorrect, why does it work fine? No compiler warnigns etc.


Because there is nothing from the compiler to complain about. The property
in question accepts a raw memory pointer. Whether you use '&' or not, you
are still passing a memory address to the property, so the compiler is
happy.


>{Attach the ADO Recordset to the main Report Table}
>Crpe1.Tables[0].DataPointer := @adoRs1; <--------------


In that case, the'&' is correct to use (though odd that they would require
that approach).

In any case, because Tables is itself a pointer to a class, and assuming
that "Tables[0]" returns a pointer (which is almost a certainty in Delphi),
then this statement:

CrpeADO->Tables[0].DataPointer = &tInterface;

If it would have to be this instead, why does it work fine as is? I
guess I really am not understanding this problem.
Quote
Would have to be this instead:

CrpeADO->Tables->Table[0]->DataPointer = &tInterface;

Or:

CrpeADO->Tables->Items[0]->DataPointer = &tInterface;

Depending on what the actual array property is named. You are trying to
apply the'[]' operator on the wrong pointer in your C++ code. In Delphi, a
class can have a "default" property. Applying the '[]' operator on a class
pointer in Delphi invokes that class's default property, so you do not have
to reference it by name explicitially. In C++, however, you cannot do that,
so you have to reference the default property by name explicitially instead.
Unless you are using BCB 6 or BDS, in which case you can deference the class
pointer in order to invoke the '[]' operator that Borland provides for
accessing the default property:

(*(CrpeADO->Tables))[0]->DataPointer = &tInterface;


Gambit


 

Re:Problem with delete vs FreeInstance()

"MrT" < XXXX@XXXXX.COM >wrote in message
Quote
I am getting confuseder and confusder!!!!(Hah)
What EXACTLY is still confusing for you?
What is the actual C++ declaration for the Tables property?
Quote
If it would have to be this instead, why does it work fine as is?
A fluke of the compiler.
Gambit
 

Re:Problem with delete vs FreeInstance()

Remy Lebeau (TeamB) wrote:
Quote
"MrT" < XXXX@XXXXX.COM >wrote in message
news: XXXX@XXXXX.COM ...


>I am getting confuseder and confusder!!!!(Hah)


What EXACTLY is still confusing for you?

What is the actual C++ declaration for the Tables property?

It leads through a long path to the Delphi classes but here is the
Crystal info:
Description
The Tables object maintains a list of Table information. There are four
general types of tables:
........
4. ActiveData datasources such as Crystal Data Object, MS ActiveX Data
Object, etc. Reports going to these types of datasources do not point
to a physical table. They point to a Field Definition File (*.TTX),
which is a text file that defines the Field types and sizes of the
virtual table. The data is then passed into such a Report at runtime by
an Active Data object. This bypasses the need of having Crystal's
runtime engine open a separate connection to the database. The Name
property of the Tables class will contain the name of the TTX file that
the Report was based on. This cannot be changed at runtime. For
ActiveData sources, use the DataPointer property to point to the new
datasource. The Tag and Bytes properties are associated with ActiveData
Reports and should be treated as read-only (they are handled by the VCL
internally).
Quote

>If it would have to be this instead, why does it work fine as is?


A fluke of the compiler.


Gambit