Symbian
Symbian OS Library

FAQ-0535 Can TKey derived classes be used with dynamic arrays ?

[Index][spacer] [Previous] [Next]



 

Classification: C++ Category: Base
Created: 10/23/2000 Modified: 09/11/2002
Number: FAQ-0535
Platform: Not Applicable

Question:
Can TKey derived classes be used with dynamic arrays ? For example to sort the array

Answer:
The answer to the question is yes the TKey derived classes can be used with dynamic arrays, but only on non-pointer based array classes eg : CArrayFixSeg, not pointer based array classes eg : CArrayPtrSeg.

Because the CArrayPtrXXX classes are derived from CArrayFix it is possible to use an existing TKey derived class, which will not result in a compilation error, however results will be far from what is expected.

The main reason for this is that the derived key classes TKeyArrayFix, TKeyArrayVar, and TKeyArrayPak provide an implementation of the TKey::At() method based upon the expectation that an array contains elements rather than pointers to elements. The TKey::At() method is used to return a pointer to the member of an element in the array which is the key element, which it does by determining an offset into the current element.

A solution to the problem is to derive a new key class from an existing key class such as TKeyArrayFix and modify the At() method so that it will correctly dereference the pointer to the element before trying to return a pointer to the key member of the element.

The following console based example demonstrates the use of a CArrayPtrSeg array and deriving a new key class from TKeyArrayFix called TKeyArrayPtr with a suitably modified At() method, which it will use to find an element within the array.


// New Key class for use with pointer based arrays

class TKeyArrayPtr : public TKeyArrayFix
{
public:
inline TKeyArrayPtr(TInt aOffset, TKeyCmpText aType)
:TKeyArrayFix(aOffset, aType) {}
inline TKeyArrayPtr(TInt aOffset, TKeyCmpText aType, TInt aLength)
:TKeyArrayFix(aOffset, aType, aLength) {}
inline TKeyArrayPtr(TInt aOffset, TKeyCmpNumeric aType)
:TKeyArrayFix(aOffset, aType) {}
virtual TAny* At(TInt aIndex) const;
};

TAny* TKeyArrayPtr::At(TInt aIndex) const
{
if (aIndex==KIndexPtr)
return *(TUint8**)iPtr+iKeyOffset;
return *(TUint8**)iBase->Ptr(aIndex*sizeof(TUint8**)).Ptr()+iKeyOffset;
}



// Do the example
LOCAL_C void doExampleL()
   {  
__UHEAP_MARK;

_LIT(KFirstElement,"First Element");
_LIT(KSecondElement,"Second Element");
_LIT(KThirdElement,"Third Element");

// Create a CArrayPtrSeg array which will maintain a list
// of pointers to CElement objects.

CArrayPtrSeg* ptrSegArray;
ptrSegArray = new (ELeave) CArrayPtrSeg(16);

// Add a few elements to the array

CElement*  ptrElement;

ptrElement = new (ELeave) CElement;
ptrElement->SetTextL(KFirstElement);
ptrElement->iNum = 11;
ptrSegArray->AppendL(ptrElement);

ptrElement = new (ELeave) CElement;
ptrElement->SetTextL(KSecondElement);
ptrElement->iNum = 12;
ptrSegArray->AppendL(ptrElement);

ptrElement = new (ELeave) CElement;
ptrElement->SetTextL(KThirdElement);
ptrElement->iNum = 13;
ptrSegArray->AppendL(ptrElement);

// Find an element using an array key. The _FOFF macro is used
// to indicate the CElement member variable iNum is the chosen
// field/value to be the search parameter.

TKeyArrayPtr aPtrNumKey(_FOFF(CElement,iNum),ECmpTInt);

// Create a reference object of type CElement and populate the
// chosen member variable (iNum) with the value to search for.

ptrElement = new (ELeave) CElement;
ptrElement->iNum = 12;

// If we find it then display its position in the array.

TInt foundPos;
TInt result = ptrSegArray->Find(ptrElement, aPtrNumKey, foundPos);

_LIT(KNotFound, "\nItem Not Found!\n");
_LIT(KFoundAtPos, "\nFound at : %d\n");

if (result>0)
console->Printf(KNotFound);
else
console->Printf(KFoundAtPos, foundPos);

delete ptrElement; // Reference object

// Delete contents of array. Because we have an array of pointers
// we are responsible for deleting the objects ourselves, prior to
// deleting the array.

TInt count = ptrSegArray->Count();

while (count--)
{
ptrElement = (*ptrSegArray)[count];
ptrSegArray->Delete(count);
delete ptrElement;
}

delete ptrSegArray;

__UHEAP_MARKEND;

}