Discussion:
Tlist->sort compare procedure gets passed same pointer for first and second parameters.
(too old to reply)
Larry Griffiths
2008-06-15 21:18:30 UTC
Permalink
I have been meaning to report this as a possible bug for quite some time but
never got around to it.

I wrote a compare procedure for the TList Sort method.
This procedure gets called with the same pointers for the first and second
parameters ( p1 and p2 ).

I think this is a bug in the sort. ( why call MyCompare when both pointers
are the same? )

I am using BDS2007 but I think it is also present in BDS2006 and BCB5.

Here is the code:

TStringList* SL;
//---------------------------------------------------------------------------
int __fastcall MyCompare( void* p1, void* p2)
{
int a = (int) p1;
int b = (int) p2;
if( SL->Strings[a] > SL->Strings[b] ) return 1;
if( SL->Strings[a] < SL->Strings[b] ) return -1;
return 0;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TList* List = new TList;
SL = new TStringList;

for( int ix = 0; ix < 5; ix++ )
{
List->Add( (void*) ix );
}

SL->Add( "Z" );
SL->Add( "A" );
SL->Add( "S" );
SL->Add( "C" );
SL->Add( "B" );

List->Sort( &MyCompare );

Memo1->Clear();
for( int ix = 0; ix < 5; ix++ )
{
Memo1->Lines->Add( SL->Strings[(int)List->Items[ix]] );
}
delete List;
delete SL;
}
Remy Lebeau (TeamB)
2008-06-16 17:23:15 UTC
Permalink
Why are you sorting using two separate lists? Your TList of indexes is
redundant in that example. You could just sort the TStringList directly
instead, ie:

int __fastcall MyCompare(TStringList *List, int Index1, int Index2)
{
return AnsiCompareStr(List->Strings[Index1], List->Strings[Index2]);
}

void __fastcall TForm1::Button1Click(TObject *Sender)
{
TStringList* SL = new TStringList;

SL->Add( "Z" );
SL->Add( "A" );
SL->Add( "S" );
SL->Add( "C" );
SL->Add( "B" );

SL->CustomSort( &MyCompare );
//
// or simply:
// SL->Sort();

Memo1->Lines->Assign( SL );

delete SL;
}


Gambit
Larry Griffiths
2008-06-17 13:08:08 UTC
Permalink
I must have sent a reply instead of a reply group, sorry Remy.

This code is only an example that somebody else beside me can compile and
run.

I was hoping that somebody else would agree with me that calling the sort
procedure with identical pointers/indexes is a bug.

Larry.
Post by Remy Lebeau (TeamB)
Why are you sorting using two separate lists? Your TList of indexes is
redundant in that example. You could just sort the TStringList directly
int __fastcall MyCompare(TStringList *List, int Index1, int Index2)
{
return AnsiCompareStr(List->Strings[Index1],
List->Strings[Index2]);
}
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TStringList* SL = new TStringList;
SL->Add( "Z" );
SL->Add( "A" );
SL->Add( "S" );
SL->Add( "C" );
SL->Add( "B" );
SL->CustomSort( &MyCompare );
//
// SL->Sort();
Memo1->Lines->Assign( SL );
delete SL;
}
Gambit
Larry Griffiths
2008-06-17 13:17:53 UTC
Permalink
I would also like to be able to pass a method pointer in the sort method
instead of a function pointer so that I do not have to use a global variable
to pass information to the sort function.

Something like this but this of course will not compile without an error...

//-------------------------------------------------------------
int __fastcall MyObject::SortFunction( void* P1, void* P2 )
{
// some sort comparison code goes here that could be multi-threaded
using multiple instances of this object.
}

or even this:

//-------------------------------------------------------------
int __fastcall MyObject::SortFunction( TObject* _Parms, void* P1, void* P2 )
{
// some sort comparison code goes here that can use a TObject Instance
so that this code could be multi-threaded.
}

void __fastcall MyObject::Main()
{
TList->Sort( this->SortFunction );
}
//-------------------------------------------------------------

Is there anyway to do this?

Larry.
Remy Lebeau (TeamB)
2008-06-17 16:35:54 UTC
Permalink
Post by Larry Griffiths
I would also like to be able to pass a method pointer in
the sort method instead of a function pointer so that I do
not have to use a global variable to pass information to
the sort function.
Sort() will not allow you to do that natively. You would have to create a
proxy wrapper function, similar to what MakeObjectInstance() does to allow
VCL WndProc() methods to be used as Win32 API WNDPROC callbacks. In fact,
I'm currently wrapping up a 3-part article series on that very subject for
C++Builder Journal (http://www.bcbjournal.com).
Post by Larry Griffiths
Is there anyway to do this?
Not directly. It would require writing low-level assembly code to make it
work. If you wait until the last part of my article series is published, I
will be providing code that would allow you to do what you are asking for.


Gambit
Larry Griffiths
2008-06-18 19:01:10 UTC
Permalink
Alas, BCB Journal requires a subscription...

Larry
Post by Remy Lebeau (TeamB)
Post by Larry Griffiths
I would also like to be able to pass a method pointer in
the sort method instead of a function pointer so that I do
not have to use a global variable to pass information to
the sort function.
Sort() will not allow you to do that natively. You would have to create a
proxy wrapper function, similar to what MakeObjectInstance() does to allow
VCL WndProc() methods to be used as Win32 API WNDPROC callbacks. In fact,
I'm currently wrapping up a 3-part article series on that very subject for
C++Builder Journal (http://www.bcbjournal.com).
Post by Larry Griffiths
Is there anyway to do this?
Not directly. It would require writing low-level assembly code to make it
work. If you wait until the last part of my article series is published,
I will be providing code that would allow you to do what you are asking
for.
Gambit
Peter Hull
2008-06-20 09:32:15 UTC
Permalink
Post by Larry Griffiths
I think this is a bug in the sort. ( why call MyCompare when both pointers
are the same? )
As I understand it, this is a property of the QuickSort algorithm;
it's not a bug as such.
I guess the overhead of a few redundant calls to MyCompare is less
than the overhead of comparing the two pointers before each and every
call. Can anyone else comment on this?

Peter

Loading...